P2375 [NOI2014] 动物园
P2375 [NOI2014] 动物园
题意是对于每个前缀,求前缀后缀不交的且前后缀相等的前后缀数量数组,\(1\le len \le 10^6\)。
考虑先求出正常的 \(next\) 数组,KMP \(O(len)\) 求解。
对于 \(next'\) 数组,可以由前一个数的 \(next'\) 数组转移,如果新数大小超过了 \(\frac{i}{2}\) 就跳到前一个 \(next\) 数组。因为如果现在已经超出长度限制,加 \(1\) 后一定超出,所以这么做是正确的。
记录 \(num\) 只需要在过程中递推一下就好了。详见代码。
时间复杂度 \(O(len)\)。
#include<bits/stdc++.h>
// #define LOCAL
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
using namespace std;
typedef long long ll;
const int N = 1e6 + 7, mod = 1e9 + 7;
ll ans;
int n,l;
char c[N];
int nex[N],num[N];
void getans () {
num[1] = 1;
int j = 0;
rep(i, 1, l - 1) {
while(j && c[i] != c[j]) j = nex[j];
if(c[i] == c[j]) j++;
nex[i + 1] = j; num[i + 1] = num[j] + 1;
}
j = 0;
rep(i, 1, l - 1) {
while(j && (c[i] != c[j])) j = nex[j];
if(c[i] == c[j]) j++;
while((j<<1) > (i + 1) ) j = nex[j];
ans = ans * (num[j] + 1) % mod;
}
}
int main () {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("my.out", "w", stdout);
#endif
sf("%d" , &n );
while (n--) {
memset(nex, 0, sizeof(nex));
memset(num, 0, sizeof(num));
ans = 1;
sf("%s", c);
l = strlen(c);
getans();
pf("%lld\n", ans);
}
}
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18435496