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;
}

 

posted @ 2019-03-07 18:42  AKCqhzdy  阅读(190)  评论(0编辑  收藏  举报