[NOI2014]动物园
刚刚又复习了一遍KMP
发现自己学了KMP之后没写过题
这道题O(n)的思路还是比较巧妙的
但是我用nlogn的暴力给整过去了
考虑暴力
找到\(pos(i<pos<=i)使得S[1~k]和S[pos-k+1,pos]相同\)
那么就可以利用\(next[i]\)表示从1~i前缀等于后缀的长度的性质
从i一直跳next直到再跳就跳到<i的位置位置
\(num[i]\)就是跳的次数
这个复杂度是O(n^2)的
但是显然可以用倍增优化跳Nxt
所以时间复杂度nlogn
#include<cstdio>
#include<cstring>
#include<algorithm>
# define LL long long
const int M = 1000005 ;
const int mod = 1e9 + 7 ;
using namespace std ;
char st[M] ;
int n , now , Nxt[20][M] , Num[M] , lg[M] ;
LL Ans ;
int main() {
int T ; scanf("%d",&T) ;
for(int i = 2 ; i <= 1000000 ; i ++) lg[i] = lg[i >> 1] + 1 ;
while(T--) {
Ans = 1 ; now = 0 ;
scanf("%s",st) ; n = strlen(st) ;
for(int i = 1 ; i < n ; i ++) {
while(now && st[i] != st[now]) now = Nxt[0][now] ;
Nxt[0][i + 1] = (st[i] == st[now] ? ++ now : 0) ;
}
for(int j = 1 ; j <= lg[n] ; j ++)
for(int i = 1 ; i <= n ; i ++)
Nxt[j][i] = Nxt[j - 1][Nxt[j - 1][i]] ;
for(int i = 2 , tot , x ; i <= n ; i ++) {
x = i ; tot = 0 ;
for(int j = lg[i] ; j >= 0 ; j --)
if((Nxt[j][x] << 1) > i)
x = Nxt[j][x] ;
for(int j = lg[i] ; j >= 0 ; j --)
if(Nxt[j][x])
x = Nxt[j][x] , tot += (1 << j) ;
Ans = (Ans * (tot + 1)) % mod ;
}
printf("%lld\n",Ans) ;
}
return 0 ;
}
然而倍增必须要有优秀的常数才能通过
所以正解是O(n)的
我们考虑前后缀可以重叠
那么可以用val[i]表示重叠的答案
这个显然可以O(n)递推出来
\(Num[i]\)就是\(val[pos]\)
\(pos\)满足\(<=i/2\)之前且\(S[i]==S[pos]\)
但是然后我们就用KMP匹配目标串的方式再对原串匹配一遍
更新答案就可以了
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define LL long long
const int M = 1000005 ;
const int mod = 1e9 + 7 ;
using namespace std ;
int n , Nxt[M] , now , val[M] ;
char st[M] ;
LL Ans ;
int main() {
int T ; scanf("%d",&T) ;
while(T --) {
now = 0 ; Ans = 1 ;
scanf("%s",st) ; n = strlen(st) ;
for(int i = 1 ; i < n ; i ++) {
while(now && st[i] != st[now]) now = Nxt[now] ;
Nxt[i + 1] = (st[i] == st[now] ? ++ now : 0) ;
}
for(int i = 1 ; i <= n ; i ++) val[i] = val[Nxt[i]] + 1 ;
now = 0 ;
for(int i = 1 ; i < n ; i ++) {
while(now && st[now] != st[i]) now = Nxt[now] ;
now += (st[i] == st[now]) ;
while((now << 1) > i + 1) now = Nxt[now] ;
Ans = (Ans * (LL)(val[now] + 1)) % mod ;
}
printf("%lld\n",Ans) ;
}
}