NOI前乱写

8.2

 

A.

考虑对每个二进制进行构造,直接给出构造方法:
while(c){ ++n; link(n,1); if(n>2) link(n-1,n); if(c&1) link(1,n); c>>=1; }
容易发现,这样可以让每一个二进制位满足条件。
 

B.

首先对所有操作的字符串建出trie树。
由于字符串总长度不大,所以可以暴力跳对应节点的祖先链来更新信息。
只要记录子树总大小,叶子个数,只有一个儿子的节点个数即可简单转移。
 

C.

首先考虑序列上怎么做,如果每个方案的权值是1那么可以简单容斥得到合法的方案数。
方案带权,那么考虑计算每一个划分方案的方案数,同样运用上面的容斥即可。
那么经过简单处理可以处理出每个颜色对应的EGF,卷起来即可得到合法的总权值。
考虑怎么处理环。
首先可以钦定第一个连续段一定是1,并且最后一个连续段一定不是1,并且给最后的答案乘上总个数.
只需要用开头是1的方案数减去开头结尾都是1的方案数即可。
发现钦定开头是1等价于给1的段数减少1,即EGF上对应的下标减少1.
于是可以计算出最后的方案数。发现这样的话会出一些小问题,就是一个包含k个连续1段的方案会被计算k次,于是在1的生成函数上继续做一些修改即可。

8.3

 

A. 欢迎来到塞莱斯特山 题

要统计每个点贡献可以想到实际上是合并子树内形成的若干段,合并的段数就是这个点被计算的次数。
于是可以想到一个 \(dp:dp[i][j]\) 表示 \(i\) 子树内形成的总段数为\(j\),段之间有序的贡献总和。
转移考虑子树归并,暴力枚举之前子树中的段数和当前字数中的段数和合并后的段数,那么发现需要求出合并的方案数,可以通过简单预处理得到。
\(O(n^3)\)
 

B. 感受清风

发现每一列是独立的,于是可以分开考虑。
对每一列建一棵线段树,修改可以直接修改,查询可以直接在线段树上二分,考虑最后两种操作怎么维护。
由于矩阵是对称的,所以可以只考虑一种操作,另一种直接翻转坐标系即可。
发现总的修改次数是线性的,所以修改的时候可以暴力将上次吹风到现在所有操作撤销,然后暴力重新做一遍所有的修改。
\(O(n \log n)\)
 

C. 我的朋友们

首先有一个 \(O(n^2)\) 的暴力 \(dp\)。发现要靠数据结构优化不是很可行,而且似乎也没有什么其他的方法,所以大概只能考虑用多项式优化了?
考虑用分治\(FFT\)来优化这个东西。
令:
\(p_i(x)=1-p[i]+p[i]*x\) \(S\) 为p的前缀积。
\(F\) 为答案的生成函数。
\(G_{l,r}(x)=S_l/S_{r-L}\)
\(f_{l,r}(x)=F_{l-1}*G[l][r]\)
那么当 \(l=r\) 时,就可以用 \(f_{l,r}(x)\) 的第 \(l\) 项来统计答案。
首先 \(G_{1,n}\) 可以通过多项式求逆得到,\(f_{1,n}=0\),考虑利用当前区间的信息向下分治。
分治过程中要注意考虑变化量来计算,因为变化量的项数是区间长度级别的。
容易发现 \([l,r]\) 区间的多项式最终只会更新 \([l,r]\) 区间的答案,这提示我们不需要保留整个多项式,只需要保留有用的项。
可以发现 \(f_{l,r}\) 最终增加的次数一定不会超过 \(r-l\),于是 \(G_{l,r}\) 就只需要保留 \(r-l\) 项。
同理,由于增加的次数只有 \(r-l\) ,那么 \(f_{l,r}\) 小于 \(l-(r-l)\) 的项最终一定不会对答案产生影响。
所以最终每个区间的多项式项数都是 \(O(r-l)\) 级别的,总复杂度 \(O(n \log^2 n)\).

posted @ 2020-08-02 20:36  tdcp  阅读(245)  评论(0编辑  收藏  举报