bzoj4044 / luoguP4762 [Cerc2014] Virus synthesis (palindromic automaton + dp)

bzoj Luogu

You use ATGC four letters spell out a given string with two operations:

1 in which a character string has been placed at the beginning or end.

2. Copy the existing string, and Reverse, followed by the head or tail of the existing string.

A beginning has an empty string. Required minimum number of operations.

Only <= 100000

Problem solution time

A non-empty string after a certain palindromic sequence is an even once after 2 operation.

So after considering dp build a PAM.

Since even only a palindromic sequence may be generated by the operation of 2, so only a palindromic sequence even participate dp.

For a point on PAM $ x $:

  • $ Y $ non-empty string if the string is removed after a two letter, then obviously $ X $ $ Y $ may be made at operation to obtain the letter before with 2, $ dp [x] = dp [y] +1 $.

  • If $ Y $ is empty, then at least two operations, $ dp [x] = 2 $.

  • $ X $ may be made of a length not exceeding $ len / 2 $ suffix extended string palindromic copying come, first multiplying jump fail to find a length of not more than $ len / 2 $ string $ y $, $ dp [x] = dp [y] + (len [x] / 2-len [y]) + 1 $.

#include<bits/stdc++.h>
using namespace std;
namespace RKK
{
const int N=100011;
char str[N];int n;
int cc(char ch)
{
    switch(ch)
    {
        case 'A':return 0;
        case 'G':return 1;
        case 'C':return 2;
        case 'T':return 3;
        default:return 114514;
    }
}
queue<int> q;
struct remilia{int tranc[4],len,fail;void set(){memset(this,0,24);}};
struct sakuya
{
    remilia p[N];
    int size,fin;
    int fa[N][20];
    int dp[N];
    void set()
    {
        p[0].set(),p[1].set();
        p[0].len=0,p[1].len=-1;
        p[0].fail=p[1].fail=1;
        memset(dp,0,(size+1)*sizeof(int));
        size=fin=1;
    }
    sakuya(){size=fin=1;this->set();}
    int match(char *s,int i,int px){return s[i-p[px].len-1]==s[i];}
    void ins(char *s,int i)
    {
        int ch=cc(s[i]);
        int npx,lpx,lpy;
        lpx=fin;
        while(!match(s,i,lpx)) lpx=p[lpx].fail;
        if(!p[lpx].tranc[ch])
        {
            npx=++size;p[npx].set();
            p[npx].len=p[lpx].len+2;
            lpy=p[lpx].fail;
            while(!match(s,i,lpy)) lpy=p[lpy].fail;
            p[npx].fail=p[lpy].tranc[ch];
            p[lpx].tranc[ch]=npx;
        }
        fin=p[lpx].tranc[ch];
    }
    int find(int x)
    {
        int l=p[x].len/2;
        for(int k=19;k>=0;k--)if(p[fa[x][k]].len>l) x=fa[x][k];
        while(p[x].len&1||p[x].len>l) x=fa[x][0];
        return x;
    }
    void work()
    {
        for(int i=0;i<=size;i++) fa[i][0]=p[i].fail;
        for(int k=1;k<20;k++)for(int i=0;i<=size;i++) fa[i][k]=fa[fa[i][k-1]][k-1];
        dp[0]=0;for(int i=0;i<4;i++)if(p[0].tranc[i]) dp[p[0].tranc[i]]=2,q.push(p[0].tranc[i]);
        int ans=n;
        while(!q.empty())
        {
            int x=q.front();q.pop();
            int f=find(x);
            dp[x]=min(dp[x],dp[f]+p[x].len/2-p[f].len+1);
            ans=min(ans,n-p[x].len+dp[x]);
            for(int i=0;i<4;i++)if(p[x].tranc[i]) dp[p[x].tranc[i]]=dp[x]+1,q.push(p[x].tranc[i]);
        }
        printf("%d\n",ans);
    }
}pam;
int TAT;
int Iris()
{
    scanf("%d",&TAT);
    while(TAT--)
    {
        scanf("%s",str+1),n=strlen(str+1);
        for(int i=1;i<=n;i++) pam.ins(str,i);
        pam.work();
        pam.set();
    }
    return 0;
}
}
int main(){return RKK::Iris();}

Guess you like

Origin www.cnblogs.com/rikurika/p/12079188.html