[CERC2014]Virus synthesis

一、題目

點此看題

二、解法

可以發現答案的構成一定是這個樣子的:一個迴文串,其它暴力填,因爲構造迴文一定比暴力填要優。

dp[i]dp[i]爲達到自動機上ii狀態所需要的步數,最終的答案是求n+dp[i]len[i]n+dp[i]-len[i]最小,爲了保證更新順序,我們用隊列來更新,更新方法如下:

  • 從父節點跳轉移而來,也就是 dp[to]=dp[t]+1dp[to]=dp[t]+1,因爲我們可以再回文翻倍之前加入我們需要的字符,所以只需要多花費11的步數。
  • 我們先處理出transtrans指針,即不大於原長度12\frac{1}{2}的最長迴文後綴,當前迴文串可以由transtrans迴文翻倍過來,我們再把不夠的部分暴力填上,所以這樣更新:dp[to]=dp[trans]+1+len[to]/2len[trans]dp[to]=dp[trans]+1+len[to]/2-len[trans]

然後transtrans的構造方法及一些細節都不說了,看代碼把qwq。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int M = 500005;
int read()
{
 int x=0,flag=1;char c;
 while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
 while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
 return x*flag;
}
int T,n,ans;char s[M];
struct Pam
{
    int n,last,cnt,fail[M],len[M],tr[M],ch[M][4],dp[M];
    void clear()
    {
        fail[0]=1;len[1]=-1;
        cnt=1;last=n=0;
    }
    int get_fail(int x)
    {
        while(s[n-len[x]-1]^s[n])
            x=fail[x];
        return x;
    }
    void ins()
    {
        n++;
        int p=get_fail(last),c=s[n]-'A';
        if(!ch[p][c])
        {
            len[++cnt]=len[p]+2;
            int tmp=get_fail(fail[p]);
            fail[cnt]=ch[tmp][c];
            ch[p][c]=cnt;
            if(len[cnt]<=2) tr[cnt]=fail[cnt];
            else
            {
                tmp=tr[p];
                while(s[n-len[tmp]-1]^s[n] || ((len[tmp]+2)<<1)>len[cnt])
                    tmp=fail[tmp];
                tr[cnt]=ch[tmp][c];
            }
        }
        last=ch[p][c];
    }
    void sol()
    {
        int ans=n;
        queue<int> q;
        q.push(0);dp[0]=1;
        for(int i=2;i<=cnt;i++) dp[i]=len[i];
        //需要賦值是因爲1爲根的狀態不會被訪問,但需要用到
        while(!q.empty())
        {
            int t=q.front();
            q.pop();//用隊列更新qwq
            for(int i=0;i<4;i++)
            {
                int to=ch[t][i];
                if(!to) continue;
                dp[to]=dp[t]+1;
                dp[to]=min(dp[to],dp[tr[to]]+1+len[to]/2-len[tr[to]]);
                ans=min(ans,dp[to]+n-len[to]);
                q.push(to);
            }
        }
        printf("%d\n",ans);
    }
}A;
int main()
{
    T=read();
    while(T--)
    {
        scanf("%s",s+1);
        n=strlen(s+1);
        for(int i=0;i<=n+1;i++)
            for(int j=0;j<4;j++)
                A.ch[i][j]=0;//不能memset,暴力mem見祖宗
        A.clear();
        for(int i=1;i<=n;i++)
        {
            if(s[i]=='C') s[i]='B';//離散一下qwq
            if(s[i]=='G') s[i]='C';
            if(s[i]=='T') s[i]='D';
            A.ins();
        }
        A.sol();
    }
}
發佈了288 篇原創文章 · 獲贊 14 · 訪問量 8915
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章