神仙题qwq
当时在某校听梁大讲课就没听懂qaq
又研究了一下Claris的题解发现好像还阔以qwq
我们可以很自然地想到回文自动机
我们令f[x]表示回文自动机上的节点x最少需要f[x]个操作
可以发现有这样几种转移
f[x]=len[x](len[x]&1==1)
f[x]=len[x]/2+1 (len[x]&1==0)
f[x]=len[x]/2-len[y]+f[y]+1(y表示x最长的不超过len[x]/2的border:由于是回文串其实就是后缀)
我们可以在回文自动机建立的时候直接找到对于每个x的y
然后接下来用bfs序更新即可
神仙题orz
//Love and Freedom. #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<queue> #define ll long long #define inf 20021225 #define N 100010 using namespace std; int id(char c){if(c=='A')return 0;if(c=='T')return 1;if(c=='G')return 2;return 3;} struct node { int ch[4],len,fail,sz; void clear() { for(int i=0;i<4;i++) ch[i]=0; len=fail=sz=0; } }t[N]; int poi,n,lst,s[N],ls[N],f[N]; void init() { s[0]=-1; t[0].len=0; t[1].len=-1; t[0].fail=1; t[1].fail=1; n=0; poi=lst=1; } void extend(int c) { int p=lst; s[++n]=c; while(s[n-1-t[p].len]!=s[n]) p=t[p].fail; if(!t[p].ch[c]) { int q=++poi; t[q].len=t[p].len+2; int np=t[p].fail; while(s[n-1-t[np].len]!=s[n]) np=t[np].fail; t[q].fail=t[np].ch[c]; t[p].ch[c]=q; if(t[q].len<=2){ls[q]=t[q].fail;} else { ls[q]=ls[p]; while(s[n-1-t[ls[q]].len]!=s[n]||(t[ls[q]].len+2)*2>t[q].len) ls[q]=t[ls[q]].fail; ls[q]=t[ls[q]].ch[s[n]]; } } lst=t[p].ch[c]; t[lst].sz++; } void clear() { for(int i=0;i<=poi;i++) f[i]=ls[i]=0,t[i].clear(); } char ch[N]; queue<int> que; void update(int &x,int y){x=min(x,y);} int main() { int T; scanf("%d",&T); while(T--) { scanf("%s",ch+1); int len=strlen(ch+1); init(); for(int i=1;i<=len;i++) extend(id(ch[i])); f[0]=1; int ans=len; for(int i=2;i<=poi;i++) if(t[i].len&1) f[i]=t[i].len; que.push(0); while(!que.empty()) { int x=que.front(); que.pop(); for(int i=0;i<4;i++) if(t[x].ch[i]) { int y=t[x].ch[i]; f[y]=f[x]+1; update(f[y],t[y].len/2-t[ls[y]].len+f[ls[y]]+1); update(ans,len-t[y].len+f[y]); que.push(y); } } printf("%d\n",ans); clear(); } return 0; }View Code