2022.03.29省选模拟赛总结

1.时间安排

7:30~8:00 看题面

T1:数据结构题,感觉十分可做,可能是可持久化trie?

T2:期望题,有10分搜索,n,m,q=15也许能状压。

T3:字符串题,对每个子串都要统计,好像很复杂,放最后做。

8:00~9:00 T1

写完第一档暴力状压枚举后,发现选出若干数不能用可持久化trie做,想了一下发现用线性基就能维护了,就预处理出来200*200的线性基过掉第二档。

因为线性基不支持撤销(也可能支持,但考场上不会写),就想到了回滚莫队,写了一份,过掉第三档。

9:00~9:20 T2

写完搜索。思考状压,没有思路,特殊分段也没想法,本来也不擅长期望题,直接跳。

9:20~10:00

一开始想的很复杂,把所有子串全列出来建个树,再dfs搜,想着太麻烦了不想写,突然一想并不需要真的建出来树跑,直接枚举左端点做n遍kmp求两遍前缀和就好了,写完大样例能过,因为想赶紧写T1就没再管了。

10:00~11:00

数据范围实在太大,而且线性基不得不带一个log,所以想有没有两个log的做法。

突然想到对于一个左端点最多只有log个本质不同的线性基,就大胆势能分析一波,线段树维护线性基,离线后扫描线做,复杂度是两个log,但是很遗憾写挂了,一直调了半个多小时都没结果,放弃这个思路。

11:00~12:00

不得不写三个log的做法,能得一点是一点,写了线段树维护线性基,但常数大的要命。

一直在卡常,最终卡到1.2s,但是无奈数据太强,三个log终究一分都没得到……

result:

T1:26 T2:10 T3:60

2.反思

T1:

为什么非要头铁去硬上线段树呢……

LYC大佬和我的三个log做法差不多,他用了ST预处理后就能轻松跑过了。

所以有时候不光\(n^2\)的数据需要预处理做,\(nlogn\)的数据也需要用类似ST预处理才能过,尤其是询问数量巨大的时候

有一个\(|v|\leq 2^4\)的数据范围没看到,这个分也是容易拿到的。

卡常数有时候并不能尽如人意,所以更多的时间应该留给更多部分分的思考,卡常数适当就行了(当然正解另说)。

与J讨论以后,认为我提出的势能分析不可做,原因:没法维护对应分界位置的线性基……

T2:

状压DP应该很容易想到的,还是因为对数学题的恐惧放弃了思考啊……

T3:

正解的规律确实太妙了,感觉自己考场上根本想不出来。

需要的数据结构并不复杂,主要是通过人类智慧找出来规律太难做到了。

不过拿了60分也不错。

3.简要题解

T1:

一句话题意:给出长度为\(n\)的数组,每次询问一个区间\(l,r\),给出参数\(d\),求在\(l\)\(r\)区间选若干个数与\(d\)异或得到的最大值。

\(n\leq1e6,|v|\leq2^30\)

弱化版:CF1100F Ivan and Burgers,(需要分治,可能是强化版?)

带时间戳线性基模板题,离线询问后扫描线,略。

T2:咕

T3:

一句话题意:给出一个字符串,对所有前缀,求这个串所有子串建出来的fail树的节点深度之和,树根的深度为-1,结果对1e9+7取模。

\(n\leq1e5\)

首先有规律:在原来串的基础上,在末尾补充一个字符,它在所有包含它的fail树中的深度值,等于它与所有原串的后缀拼接起来的字符串在原串出现的次数之和。

如果不想证明的话可以打表,证明的话如果上一次出现的位置dep=0,新字符的dep是1,否则说明上一次出现的位置还能继续匹配相同的前缀,直到dep=0,而这些前缀也必然可以和新加入字符拼接后缀的字符串匹配,可以归纳一下。

得到结论后,对原串跑SAM建出来parent树,对字符串中每个字符对应在parent树上的位置进行到根节点1的路径加,加的值就是该节点的endpos集合大小。

树链剖分维护一下,求答案做两遍前缀和,一遍是dep的前缀和,一遍是最终答案的前缀和,就做完了。

4.总结

1.时间安排

时间不应该浪费在调bug和卡常数这种事情上,有可能浪费了大把时间和精力最后做了无用功。

避免调bug的话,首先应该先确定算法的正确性,算法假了怎么调都是白费功夫;其次就是分模块去调试,实现一个比较麻烦的函数就简单测试一下正确性,否则最后混到一起找谁是错的就要费半天功夫。

避免卡常数的话,数据结构题最常见,FastIO常备,register、inline不厌其烦在写初版代码时就加上,其他回头想到再说。

2.数学题

虽然数学题一直以来都是我的弱项,但是也不能因为不擅长就不敢思考。

数学题数据要么太小要么太大,对于小数据题目,正解往往都是复杂度很高比如\(n^3\)的dp,所以\(n^4\)甚至\(n^5\)这样的高复杂度dp还是要大胆去想的,不能只吃爆搜的保底。

3.带时间戳线性基

有人也叫这个可删除线性基,学到了新知识。

其基本思想有点类似可持久化数据结构,对于每个二进制位打上插入时的时间戳。

做插入操作时,如果此二进制位已经有数了,根据线性基的定义,把这个数更改为当前要插入的数,线性基的功能不会改变,但是比原来数插入时间小的询问不可以使用当前这位的线性基,所以需要更新时间戳。

查询时就像可持久化数据结构一样,比较时间戳就好了。

模板代码:

struct Basic{
	int buc[30],tim[30];
	void insert(int x,int t){
		for(int i=29;i>=0;i--){
			if((x>>i)&1){
				if(buc[i]){
					if(tim[i]<t){
						swap(buc[i],x);swap(tim[i],t);
					}
					x^=buc[i];
				}
				else{
					buc[i]=x;tim[i]=t;
					break;
				}
			}
		}
	}
	int get(int x,int lim){
		for(int i=29;i>=0;i--){
			if((x^buc[i])>x&&tim[i]>=lim)
			x^=buc[i];
		}
		return x;
	}
}B;
posted @ 2022-03-29 14:41  Displace  阅读(29)  评论(0)    收藏  举报