Loading

【游记】CSP2019游记

本来不想写的,结果还是写了(别问我为什么

\(Day1\ T1\)

格雷码,开题发现题面很长,预感不好

问题的本质是提供格雷码的构造方法,求构造有序集合中的第\(K\)个格雷码

开始想着如何去推公式(某凯的疑惑),半个小时没推出来,只好回去想如何去优化模拟

显然我们并不用把前\(K\)个格雷码全部列出来,显然对于\(N\)位格雷码,前\(2^{N-1}\)个格雷码第一位是\(0\),后面的第一位是\(1\)

这样我们可以进行类似线段树查询的递归,时间复杂度\(O(log_2N)\)

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
int n;ull k;
void dfs(int now,ull res){
	if(!now)return;
	ull sum=1ull<<(now-1);
	//cout<<now<<" "<<sum<<" "<<res<<endl;
	if(res<=sum){printf("0");dfs(now-1,res);}
	else{printf("1");dfs(now-1,sum*2-res+1);};
}
int main()
{
	cin>>n>>k;
	k++;
	if(!k){
		putchar('1');
		for(int i=1;i<64;i++)printf("0");
		return 0;
	} 
	dfs(n,k);
	return 0;
 } 

\(Day1\ T2\)

括号树,考场想出正解,见这里

恶臭样例不说了

\(Day1\ T3\)

本来想着\(Day1T3\)人均\(100\),推来推去连部分分都拿不到,

难道爆0滚粗,显然不行

\(DFS\)枚举删边顺序,\(O(N)Check\)一下

结果输入格式错了,调了一个小时不知道哪错了(10分都没了

出考场发现人均\(100+100+10=210\),只有\(100+100+0=200\),貌似差的不是很多(自我安慰一下

\(Day2\ T1\)

背景和题面很神奇(然而我并不知道出处

看题,感觉不是\(DP\)就是组合数学

简化题意

给定一个矩阵,从中选出一些点,使得每行最多选1个,每列选的个数不超过选的总个数的一半,一定要选

每行最多选一个的条件很好满足啊,貌似直接乘法原理可做

然后发现列的条件奇奇怪怪,一下子想不到怎么写,开\(T2\)去了

后话(撑死没想到容斥

重新看题,发现数据范围很奇怪,\(64pts->M\le3\),M这么小,放状压过吗

想半天发现状压不可做,慌,想到出场是人均\(AK\),欸自闭

再暴力点,\(f[i][u][v][k]\)表示\(1-i\)行选了\(u\)个第一列的数,\(v\)个第二列的数,\(k\)个第三列的数,直接枚举每一行选择的数进行转移即可,时间复杂度\(O(N^{M+1})\)\(64pts\)有了

\(Day2\ T2\)

我说这式子怎么这么熟悉啊,这不是斜率优化标准式子啊

直接上\(DP\),\(f[i][j]\)表示上一个分割点在\(i\),这一个分割点在\(j\)

枚举\(k\)\(f[i][j]=min\{f[j][k]+{(sum_i-sum_j)^2}\}\),其中\(sum_i-sum_j>sum_j-sum_k\)

考虑斜率优化,md谁来教我这鬼式子怎么斜率优化啊啊啊啊啊啊

想了半个小时斜率优化无果,考虑改变策略

发现这么方程具有决策单调性,枚举\(j\),再顺序枚举\(i\)\(k\)的取值范围单调递减

这样我们只用两重循环即可(队列都不要

\(O(N^2)\ \ 64pts!\)

\(Day2\ T3\)

题面貌似很复杂,但题意很简单,就是每次切断一条边,得到两个子树,求这些子树的重心的编号和

枚举切的边,然后\(O(N)\)求重心(刚好考前看过

\(O(N^2)\)\(40pts\)

考虑链的情况,显然我们从链的一端开始遍历,\(dfn\)单调递增,这样我们就可以快速求出每次切边后得到的两条新链的中点,而链的中点就是重心

这样就有\(55pts\)

本来想推完全二叉树,没时间了不敢莽

出考场对了一下,发现写的都是对了

这样总分\(100+100+0+64+64+55=383\)

\(luogu\)人均\(100+100+10+100+88+75=473\)

我还是太菜了


周一打电话说tm程序弄丢了(回去重考

就nm离谱

心态炸了,迷迷糊糊进了考场

话说第二次考是正式了点(座位不再随便坐,上个厕所还要登记……


\(Day3\ T1\)

题面短,一眼水题

如果本身是合法日期输出\(0\)

枚举修改一个位置的数,如果能改为合法日期,输出\(1\)

否则输出\(2\)

\(O(1),100pts\)


\(Day3\ T2\)

一看双重\(\sum\)有点慌

分析一下,枚举\(l,r\)\(\sum\)可以用前缀和\(O(1)\)求,这样\(O(N^2)\)就有\(70pts\)

将式子简化\(Ans=\sum^n_{l=1}\sum^n_{r=l}(sumA_r-sumA_{l-1})(sumB_r-sumB_{l-1})\)

然后展开\(Ans=\sum^n_{l=1}\sum^n_{r=l}(sumA_r*sumB_r-sumA_{l-1}*sumB_r-sumB_{l-1}*sumA_r+sumA_{l-1}*sumB_{l-1})\)

分别对\((sumA_{l-1}*sumB_r)\),\((sumB_{l-1}*sumA_r)\),\((sumA_{l-1}*sumB_{l-1})\),记录前缀和

这样我们二次前缀和就解决了问题

\(O(N),100pts\)

注意负数取模

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define P 1000000007
using namespace std;
int n;long long a[500005],b[500005],sa[500005],sb[500005],s[500005];
long long ans=0;
int main(){
	scanf("%d",&n);
	rep(i,1,n)scanf("%lld",&a[i]),a[i]=(a[i]+a[i-1])%P,sa[i]=(a[i]+sa[i-1])%P;
	rep(i,1,n)scanf("%lld",&b[i]),b[i]=(b[i]+b[i-1])%P,sb[i]=(sb[i-1]+b[i])%P;
	rep(i,1,n)s[i]=(s[i-1]+a[i]*b[i])%P;
	//rep(i,1,n)printf("%d %d %d %d %d\n",a[i],b[i],sa[i],sb[i],s[i]);
	rep(i,1,n)ans=((ans+(i*a[i]%P*b[i]%P-a[i]*sb[i-1]%P-sa[i-1]*b[i]%P+s[i-1])%P)%P+P)%P;
	printf("%lld\n",ans);
	return 0;
}

\(Day3\ T3\)

题面就是给一个奇奇怪怪的网格图,求最小生成树

\(Kruscal\ 64pts\)

剖析\(Kruscal\)的本质,边权相等的边排序后在一起,这样我们对一行/一列的边一起加,记录下已经加过的行和列,避免成环

这样\(O(NlogN),100pts\)

我就这样信心满满走出考场

没开long long,我太难了

沦为和暴力老哥同分

自闭


\(Day3\ T4\)

真正送我自闭的题目

题面长而毒瘤

目测大模拟

不管先暴力模拟一遍

\(2\ hours\ later...\)

md这第\(3\)个样例是什么东西啊

后来临时突然改样例这是什么操作啊

换了个样例再测还是没过

自闭

换了2个思路,重构了3次还是没模拟出来

真自闭了

还有半个小时才想到还有一道题我,我,我……


\(Day3\ T5\)

众所周知\(wlq\)他炸了

所以这题看完题就没时间了,检查下文件就出考场了

想到可能是并查集加计数\(DP\)


出考场人均\(300+\),然后我没了

\(100+100+100+4+0=304\)

结果\(T3\)没开longlong

\(100+100+64+12=276\)

然后就没有然后了


总结\(Wlq\)太菜了

考试经验不足,考试心态不好,水平有限才是失败的根本原因

改变训练模式,\(CSP2020\)我还回来


补充:机房scw太惨了\(T1\)文件名写错,表示深切的同情

posted @ 2021-10-04 16:47  7KByte  阅读(55)  评论(0编辑  收藏  举报