卧薪尝胆,厚积薄发。
回文后缀
Date: Sat Dec 29 20:34:06 CST 2018 In Category: NoCategory

Description:

给定字符集大小 $S$ ,问有多少个长度为 $N$ 的字符串不存在长度 $>1$ 的回文后缀。
$1\leqslant n\leqslant 10^7$

Solution:

首先统计 $f[i]$ 表示长度为 $i$ 的不含回文后缀的回文串个数,那么答案就是: $$ ans=S^n-\sum_{i=2}^nf[i]S^{n-i} $$ 考虑预处理 $f$ 的过程,直觉告诉我们答案应该是: $$ f[n]=S^{\lceil\frac n 2\rceil}-\sum_{i=2}^{\lceil\frac n 2\rceil}f[i]S^{\lceil\frac n 2\rceil-i} $$ 但是后面那个 $\lceil\frac n 2\rceil$ 并不是很好理解,其实这是因为如果一个回文串有一个大于 $\lceil\frac n 2\rceil$ 的回文后缀,那它一定还有一个小于 $\lceil\frac n 2\rceil$ 的回文后缀,如果都减掉的话肯定是不对的。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n,s,m;
#define MAXN 10000010
int f[MAXN];
int pows[MAXN];
int sum[MAXN];
int main()
{
freopen("suffix.in","r",stdin);
freopen("suffix.out","w",stdout);
scanf("%d%d%d",&n,&s,&m);
pows[0] = 1;
for(int i = 1;i <= n;++i)pows[i] = 1ll * pows[i - 1] * s % m;
for(int i = 2;i <= n;++i)
{
f[i] = (pows[(i + 1) / 2] - sum[(i + 1) / 2] + m) % m;
sum[i] = (1ll * sum[i - 1] * s % m + f[i]) % m;
}
int ans = pows[n];
for(int i = 2;i <= n;++i)
{
ans = (ans - 1ll * f[i] * pows[n - i] % m + m) % m;
}
cout << ans << endl;
fclose(stdin);
fclose(stdout);
return 0;
}
In tag: DP-计数DP
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡