2021-05 杂题泛做

Codeforces 1043G

不难证明出现的答案答案是不大于 \(4\) 的,否则是 \(-1\),构造形如:\(BACAD\)

直接分开讨论四种答案对应的若干情况

  • \(AAAA\dots\) 的是\(lcp\)

  • \(AAB,BAA\) 写一个优秀的拆分,\(ABA\) 是查 \(\rm{border}\)

    考虑这样一个结论:子串存在的长度 \(\ge \sqrt n\)\(border\) 一定满足 \(l\)\(st\) 的后缀数组上的排名不超过 \(\sqrt n\)

    证明考虑如果有超过 \(sqrt\) 个后缀满足在这两个中间,那么其和两端的 \(\rm{LCP}\) 都大于 \(\sqrt n\),明显不存在

  • \(\rm{ABAC,BACA}\) 这个部分直接判是不是两端的字符出现了两次即可

    \(\rm{BAAC}\) 写出来优秀的拆分之后维护 \(l_i\) 表示从当前点开始最小的位置满足该子串是一个 \(AA\) 串,是一个 \(RMQ\)

四合一挺难受的

平面最近点对

记录本题分治做法

考虑和建立 \(\rm{KD-Tree}\) 的做法类似的,对于当前分治区间 \([l,r]\),取 \(x\) 这维的中位数,递归左右部分,求得两个子集的 \(\min\)

考虑合并两边的信息不难发现只有 \(\rm{[Mid_x-\min,Mid_x+\min]}\) 中的点有用

将区间里面的点按照 \(y\) 轴归并之后将这些点取出,写一个带朴素剪枝的暴力即可

考虑这个暴力的正确性:

对于一个点,可能更新答案的点必然在不大于 \([\min\times 2\min]\) 的一个矩形里面

将其分割成 \(2\times 3\) 的几个小部分,那么每个矩形框里必然不能有超过 \(1\) 个点,小矩形对角线的长度为 \(\frac{5}6 \min\),那么复杂度正确,而且常数不大

Luogu3322

关注到是一个深度为 \(n\) 的线段树的形式,那么这个操作的先后顺序和是不是能翻成一个标准序列无关

所记录的东西就是操作的次数,并从小向大 \(\rm{dfs}\),最后 ans+=fac[num];

那么找到所有不是 \(+1\) 递增的段,如果超过两个一定不合法,剩下的枚举所有情况交换递归

注意在不合法状态有 \(2\) 个的情况下,如果得到左 \(1\) 的解可以不枚举右 \(2\),通过这样的剪枝得到的复杂度为 \(2^{24}\)

联通欧拉图计数

定义是能经过每个边恰好一次并回到出发点的图

\(f_i\) 表示有 \(n\) 个点的欧拉图的数量(不保证联通),因为图的性质(每个点度数都是偶数),那么结果是 \(2^{\binom {i-1}2}\)

设联通欧拉图的数量为 \(g_i\),枚举 \(1\) 号点所在的联通块的大小

\[g_i=f_i-\sum_{j=1}^{i-1} \binom{i-1}{j}f_j g_{i-j} \]

想要分治 \(NTT\) 的话好像也不是不行,拆开组合数做即可

Codeforces986E

差分询问,运用质数个数少,次数小等和 \(gcd\) 本质是次数取 \(\min\) 等性质 \(dfs\) 处理即可

Codeforces809E

首先得到这样一个东西:

\[\varphi(a_i\times a_j)=\frac{\varphi(a_i)\times \varphi(a_j)\times gcd(a_i,a_j)}{\varphi(gcd(a_i,a_j))} \]

证明直接拿质因子拆就行了,式子变成:

\[\rm{\frac1{2(n-1)n}\sum_{i=1}^n\sum_{j=1}^n \frac{\varphi(a_i)\times \varphi(a_j)\times gcd(a_i,a_j)}{\varphi(gcd(a_i,a_j))}\times dist(i,j)} \]

显然枚举 \(gcd,\) 接着把 \(a_i\) 扔到其所有因子的 \(\rm{vector}\) 里面,设如下两个函数(没想到吧,竟然是标准的莫比乌斯反演式!)

\[\frac1{2(n-1)n}\sum_{d=1}^{n} \frac{d}{\varphi(d)} \sum_{i=1}^n\sum_{j=1}^n[(a_i,a_j)=d]\varphi(a_i)\varphi(a_j)dist(i,j) \]

\[f(x)=\sum_{i=1}^n\sum_{j=1}^n[(a_i,a_j)=x]\varphi(a_i)\varphi(a_j)dist(i,j)=\sum_{d|x}F(d) \]

\[F(x)=\sum_{x|d}\mu(\frac{d}x) f(d)=\sum_{x|d}\sum_{i=1}^n\sum_{j=1}^n[d|(a_i,a_j)]\varphi(a_i)\varphi(a_j)dist(i,j) \]

那么把 \(dist\) 拆开,对每个质因子整个虚树就能得到 \(F(d)\)

因为要求 \(n\log n\)\(LCA\),那么建议使用倍增

本来还想拆 \(\varphi=\mu * Id\) 的,同时学会了简单证明了这个式子

Codeforces639F

不难发现题目中要求的就是一个边双,那么先把原图按照边双整成一个森林

对于每个询问,把边和点的所有集合全拉出来建虚树森林,在上面照样跑边双就行了

如何写边双?

inline void tarjan(int x,int pre){
	dfn[x]=low[x]=++tim;
    for(reg int i=head[x];i;i=e[i].nxt){
    	int t=e[i].to; if(!dfn[t]){
        	tarjan(t,i); low[x]=min(low[x],low[t]);
            if(low[t]>dfn[x]) bridge[i]=bridge[i^1]=1;
       	}else if(i!=(pre^1)) low[x]=min(low[x],dfn[t]);
    } return ;
}

点双直接判是不是 \(dfn[x]\le low[t]\) 然后弹栈,记割点如下

if(x!=rt||cvcc>1) cut[x]=1

其中 \(\rm{rt}\)\(\rm{tarjan}\) 开始的地方

Codeforces925E

有一些显然的思考是把每个点的点权先整成 \(-t_i\),有变成白点的操作就给链加

先树剖,然后对树分块,每次修改暴力跳重链按题意模拟即可

Codeforces896C

使用珂朵莉树,其本质是使用了数据随机的情况下会有 \(\frac{1}4\) 的概率是区间覆盖操作

大体就是维护一个里面表示区间的 \(set\),每个区间的值是相同的

核心函数就是 assign(),split(),分别表示将区间覆盖和拆开区间,剩下全是直接暴力

实现上有些新的语法:

  • mutable: 能避开 \(\rm{set}\) 里面的 \(\rm{const}\) 限制

  • erase(iterator_L,iterator_R): 删掉 \(\rm{set}\) 里面 \(\rm{[L,R)}\) 的迭代器

BZOJ3786

\(\rm{Euler \ Tour \ Tree}\) 用欧拉序(\(\rm{in,out}\) 各在序列里面加入一次 )来维护子树

外层不论套 \(\rm{splay}\) 抑或是 \(\rm{fhq\_Treap}\) 都可以直接对着序列来交换子树

但是最大的局限性一是维护森林将十分复杂,二是不能换根

本题树上维护 \(\rm{tag}\) 即可,再附 \(\rm{fhq\_Treap}\) 的写法

inline int merge(int x,int y){
    if(!x||!y) return x+y; 
    push_down(x); 
    push_down(y); 
    if(rand()%(sz[x]+sz[y])<sz[x]){
    	rs[x]=merge(rs[x],y);
        push_up(x);
        return x;
    }else{
    	ls[y]=merge(x,ls[y]);
        push_up(y);
		return y;
    }
}
inline void split(int rt,int siz,int &x,int &y){
    if(!rt) return x=y=0,void(); 
    if(sz[rt]==siz) return x=rt,y=0,void(); 
    if(!sz[rt]) return x=0,y=rt,void(); 
    push_down(rt); 
    if(sz[ls[rt]]>=siz){
    	split(ls[rt],siz,x,ls[rt]);
        y=rt,fa[x]=0;
    }else{
    	split(rs[rt],siz-sz[ls[rt]]-1,rs[rt],y);
        x=rt,fa[y]=0;
    }return push_up(rt);
}

Codeforces878C

不难发现如果两个选手不是所有维度大小性相同,那么都有可能获胜

所以对于这样的选手缩一把点,维护一个点的个数

考虑到 \(set\) 的判等方式是两者的 \(\rm{operator:<}\) 都不成立,那么使用 \(\rm{set}\) 维护一个集合里面的维度最值和集合的大小即可

答案也就是 “最大” 的集合的大小

Luogu4426

考虑树上独立集的求法,暴力 \(dp\) 可以获得 \(\rm{10\ pts}\) 的好成绩

直接套到图上面不太可取,其实冲突的地方只有非树边 \(=m-n+1\le 11\)

  • 我会二进制枚举!

    \(2^{11}\) 次方枚举每条边是上侧点选还是下侧点选,剩下的还是一个朴素 \(dp\)

    值得注意的是可以能有 \(E_1\) 的下侧点是 \(E_2\) 的上侧点,所以标记的时候要稍微复杂一点

  • \(\rm{Key\ Observation}\):有很多的 \(dp\) 是没有用的,同时如果不在任意一对非树边涉及的点的路径上的点的 \(dp\) 永远不变

    建立这 \(22\) 个点的虚树,别的状态的 \(dp\) 值可以提前预处理出来,剩下的 \(dp\) 照样二进制枚举做即可

时间复杂度 \(\Theta(n+11\times2^{11})\)

posted @ 2021-05-23 15:36  yspm  阅读(65)  评论(0编辑  收藏  举报