E2. Beautiful Patterns (Hard Version)
首先结论:对于两个子数组,若他们回文中心不重合,则他们各自为回文串这两件事互相独立。
一个子数组回文,设该子数组长为\(len\),即相当于对这个子数组产生$ \left \lfloor \frac{len}{2}\right \rfloor$个约束:
\(a_{l}=a_{r},a_{l+1}=a_{r-1},...\)
若两子数组回文中心不重合,则对于两个子数组产生的约束一定不会出现重复,故而两者同时发生的概率等于所有约束同时发生的概率,也即两个子数组各自的约束发生概率的乘积
而如果出现回文中心重合,则会出现约束的重复,此时两者同时回文的概率等于较长子数组回文的概率。
令\(x_{l,r}\)表示区间 $[l,r] $ 回文的概率
要求\(E(\sum^2x_{l,r})\)
\(E(\sum^2x_{l,r}) = E(\sum x_{l,r} \sum x_{l,r})=E(\sum \sum x_{l_{1},r_{1}}x_{l_{2},r_{2}})\)
即变成求任两个区间同时回文的概率总和。
首先求出任意区间回文的概率总和\(P\)
首先规定\(si_{i}\)表示\(\frac{1}{m^i}\),\(sm_{i}\)表示\(\sum_{0}^{i} si_{l}\)
那么对于求\(P\),首先对于每一个以当前位置为回文中心的情况,对当前位置首先算约束个数\(L=min(i-1,n-i)\)
那么将\(sm_{L}\)贡献到\(P\)
其次对于以当前位置到下一个位置之间为回文中心的情况,约束个数\(L=min(i,n-i)\)
则将\(\sum_{1}^{L} si_{i}\),即\(sm_{L}-1\)贡献到\(P\)
算出\(P\)后,利用\(P\)算每个回文中心对答案的贡献。对于以某个下标作为回文中心的情况,利用以下容斥,设\(L=min(i - 1,n - i)\),则贡献为:
\(\sum_{0}^{L}si_{i}*(P-sm_{L})+sm_{L}-sm_{i}+(i+1)*si_{i}\)
而两位置之间作为回文中心的情况是类似的,这时候产生的新量也需要提前预处理。
代码:
void solve() {
cin >> n >> m >> mod;
Z::setMod(mod);
vector<Z> si(n + 10),sm(n + 10);
vector<Z> s1(n + 10),s2(n + 10),s3(n + 10),ss(n + 10);
si[0] = 1;
for(int i = 1;i <= n;i++) si[i] = si[i - 1] / m;
sm[0] = 1;
for(int i = 1;i <= n;i++) sm[i] = sm[i - 1] + si[i];
s1[0] = 1;
s2[0] = 1;
for(int i = 1;i <= n;i++) {
s1[i] = s1[i - 1] + sm[i];
s2[i] = s2[i - 1] + (i + 1) * si[i];
s3[i] = s3[i - 1] + i * si[i];
ss[i] = ss[i - 1] + si[i];
}
for(int i = 1;i <= n;i++) ss[i] = ss[i - 1] + ss[i];
Z P = 0;
for(int i = 1;i <= n;i++) {
int L = min(i - 1,n - i);
P += sm[L];
if(i < n) {
L = min(i,n - i);
P += sm[L] - 1;
}
}
Z ans = 0;
for(int i = 1;i <= n;i++) {
int L = min(i - 1,n - i);
ans += sm[L] * (P - sm[L]) + (L + 1) * sm[L] - s1[L] + s2[L];
if(i < n) {
L = min(i,n - i);
ans += (sm[L] - 1) * (P - sm[L] + 1) + L * (sm[L] - 1) - ss[L] + s3[L];
}
}
cout << ans << '\n';
}

浙公网安备 33010602011771号