bzoj4044: [Cerc2014] Virus synthesis
做题要冷静啊。。
仔细分析一下题面会发现这样造串的方式,对于任意一个串一定是前面一堆+一个偶回文+后面一堆
答案就是把某一个回文造出来的代价+n-这个回文的长度
还有就是翻转永远不会劣于加字符
那么把回文自动机造出来,把每个回文的最小步数搞出来就好了
假如是奇回文,直接f[pre]+2
偶的话分成两种情况,由pre转移过来和不由pre转移
对于偶回文,最后一步一定是翻转,那么从pre转移过来就是f[pre]+1,因为可以在pre翻转之前先加一个字符
反之,就必须利用当前回文的最后一个字符,也就是把当前回文的一半搞出来
倍增跳fail找到第一个len*2<= now len 的点,用它翻转再补满一半再翻转一次,就是f[u]+nowlen/2-len+1
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int _=1e2; const int maxn=1*1e5+_; const int maxc=4+3; const int mbit=17+3; int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } void write(int x) { if(x>=10)write(x/10); putchar(x%10+'0'); } int n,a[maxn];char ss[maxn]; void zxcv(int i) { if(ss[i]=='A')a[i]=1; else if(ss[i]=='C')a[i]=2; else if(ss[i]=='G')a[i]=3; else a[i]=4; } struct Pnode { int w[maxc],len,dep,fail[mbit]; void clear() { len=0;dep=0; memset(w,0,sizeof(w)); memset(fail,0,sizeof(fail)); } };//fail树中的深度,倍增找祖先 struct PAM { Pnode ch[maxn];int cnt,last; void init() { cnt=1;last=1; ch[0].clear(),ch[1].clear(); ch[0].len=0,ch[1].len=-1; ch[0].fail[0]=1; ch[0].dep=1; } int f[maxn]; void insert(int k,int x) { int pre=last; while(a[k]!=a[k-1-ch[pre].len]) pre=ch[pre].fail[0]; if(ch[pre].w[x]==0) { int now=++cnt; ch[now].clear(); ch[now].len=ch[pre].len+2; ch[now].dep=ch[pre].dep+1; int ppre=ch[pre].fail[0]; while(a[k]!=a[k-1-ch[ppre].len])ppre=ch[ppre].fail[0]; ch[now].fail[0]=ch[ppre].w[x]; for(int i=1;(1<<i)<=ch[now].dep;i++) ch[now].fail[i]=ch[ch[now].fail[i-1]].fail[i-1]; ch[pre].w[x]=now; //.........update............. if(ch[now].len==1)f[now]=1; else if(ch[now].len==2)f[now]=2; else if(ch[now].len%2==1)f[now]=f[pre]+2; else { f[now]=f[pre]+1; int u=now,b=0; while(1) { while(b>=0&&((1<<b)>ch[u].dep||ch[ch[u].fail[b]].len*2<=ch[now].len))b--; if(b<0)break; u=ch[u].fail[b]; b++; } u=ch[u].fail[0]; if(u!=0&&u!=1) f[now]=min(f[now],f[u]+ch[now].len/2-ch[u].len+1); } //..........getf.............. } last=ch[pre].w[x]; } }P; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int T; T=read(); while(T--) { scanf("%s",ss+1);n=strlen(ss+1); P.init(); for(int i=1;i<=n;i++) { if(i==21) { int t;t++; } zxcv(i),P.insert(i,a[i]); } int ans=(1<<30); for(int i=2;i<=P.cnt;i++) { ans=min(ans,P.f[i]+n-P.ch[i].len); } write(ans);puts(""); } return 0; }
pain and happy in the cruel world.