P4762 [CERC2014]Virus synthesis

最后一定是一个大回文串+一些暴力边角。

多维护一个转移 \(tra[p]\),表示 \(\leq \frac{len[p]}{2}\) 的后缀位于的状态。

显然有两种转移:

  • 直接填一个字符,\(f[v]=f[u]+1\)
  • \(tra[p]\) 反转+暴力添加字符得来。

利用拓扑排序DP即可。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=100010;
int T,n,tot,lst;
int fa[N],c[N][4],len[N],f[N],tra[N];
char s[N];
inline int cvt(const char& ch) {
  if(ch=='A') return 0;
  if(ch=='C') return 1;
  if(ch=='G') return 2;
              return 3;
}
inline int jmp(int p,int i) 
  {while(s[i-len[p]-1]!=s[i]) p=fa[p]; return p;}
inline void ext(int ch,int i) {
  R p=jmp(lst,i); if(!c[p][ch]) {
    R np=++tot; f[np]=len[np]=len[p]+2;
    R t=jmp(fa[p],i); 
    fa[np]=c[t][ch],c[p][ch]=np;
    if(len[np]<=2) tra[np]=fa[np];
    else {
      t=tra[p];
      while(s[i-len[t]-1]!=s[i]||(len[t]+2)*2>len[np]) t=fa[t];
      tra[np]=c[t][ch]  ;
    }
  } lst=c[p][ch];
}
queue<int> q;
int ans;
inline void main() {
  T=g(); s[0]='#';
  while(T--) {
    scanf("%s",s+1),n=strlen(s+1);
    memset(c,0,(tot+1)*16);
    len[fa[fa[1]=lst=0]=tot=1]=-1;
    for(R i=1;i<=n;++i) ext(cvt(s[i]),i);
    ans=n;
    for(R i=0;i<4;++i) if(c[0][i]) q.push(c[0][i]);
    while(q.size()) {
      R u=q.front(); q.pop();
      f[u]=min(f[u],f[tra[u]]+1+len[u]/2-len[tra[u]]);
      ans=min(ans,n-len[u]+f[u]);
      for(R i=0;i<4;++i) if(c[u][i]) {
        R v=c[u][i];
        f[v]=min(f[v],f[u]+1);
        q.push(c[u][i]);
      }
    }
    printf("%d\n",ans);
  }
}
} signed main() {Luitaryi::main(); return 0;}

2020.01.16

posted @ 2020-01-16 20:07  LuitaryiJack  阅读(111)  评论(0编辑  收藏  举报