总
复杂度证明比起 SAM 较简单(虽然我还是没想出来),用学长魏忠浩的一句话就行了:
考虑当前点 fail 指针指向的节点的长度,跳一次至少减,插入至多加常数
难点在于代码细节,想不去讨论初始情况的一坨就必须注意细节。
CODE
#include<bits/stdc++.h> #define fru(i,j,k) for(int i=j;i<=k;++i) #define frd(i,j,k) for(int i=j;i>=k;--i) #define pc(x) putchar(x) #define fio(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout) using namespace std;using ll = long long; namespace ugi{ char c=' '; int in(void) { int x=0;bool f=false; while(!isdigit(c)){f^=c=='-';c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } } using ugi::in; const int maxn=(int)(5e5+12); int n,nl[maxn]; char str[maxn]; int ch[26][maxn],fail[maxn],len[maxn],cnt,lt=1; void init(void) { cnt=1;len[0]=0;len[1]=-1;fail[0]=1; } int getpt(int p,int x) { while(str[p]!=str[p-len[x]-1]) { x=fail[x]; } return x; } int main() { scanf("%s",str+1);n=strlen(str+1); int la=0,c; init(); fru(i,1,n) { str[i]=(str[i]-97+la)%26+97;c=str[i]-'a'; lt=getpt(i,lt); if(!ch[c][lt]) { len[++cnt]=len[lt]+2; fail[cnt]=ch[c][getpt(i,fail[lt])]; ch[c][lt]=cnt; nl[cnt]=nl[fail[cnt]]+1; } lt=ch[c][lt]; printf("%d ",la=nl[lt]); } return 0; }
|