「HDU6583 Typewriter」 - 后缀自动机

HDU6583 Typewriter

tags:后缀自动机

题意

一开始你有一个空串,你有两种操作,一是向这个串的末尾加上任意小写字母,代价为 \(p​\), 二是向这个串的末尾加上这个串的任意一个子串,告诉你最终状态,让你求最少要多少代价才能变成最终状态

题解

\(f_i\) 表示变成 \(s[1,i]\) 的最小代价

那么对于第一种操作 \(f_i=f_{i-1}+p\)

对于第二种操作 \(f_i=f_{j-1}+q\), 其中, \(s[j,i]\)\(s[1,j-1]\) 种出现过

第一种很好转移,第二种用后缀自动机维护,由于 \(j\) 是单调的,所以在 \(j\) 向右移时将 \(s_j\) 加入 SAM, 然后维护 \(s[l,r]\) 的节点即可,时间复杂度是 \(O(n)\)

#include<cstdio>
#include<cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
template<typename T>inline void rd(T&x){int fl=0,ch;while(ch=getchar(),ch<48||57<ch)fl^=!(ch^45);x=(ch&15);while(ch=getchar(),47<ch&&ch<58)x=x*10+(ch&15);if(fl)x=-x;}
template<typename T>inline void pt(T x){if(x<0)putchar('-'),x=-x;if(x>9)pt(x/10);putchar(x%10+48);}
template<typename T>inline void pt(T x,int ch){pt(x),putchar(ch);}
template<typename T>inline T max(const T&x,const T&y){return x<y?y:x;}
template<typename T>inline T min(const T&x,const T&y){return x<y?x:y;}
typedef long long ll;
const int N=200005;
int n,w1,w2,f[N];char s[N];ll ans;
struct SAM{
    int cnt,lst,fa[N<<1],ch[N<<1][26],len[N<<1];
    SAM(){cnt=lst=1;}
    void clear(){
        for(int i=1;i<=cnt;++i)fa[i]=len[i]=0,memset(ch[i],0,sizeof(ch[i]));
        cnt=lst=1;
    }
    void extend(int c){
        int p=lst,np=lst=++cnt;len[np]=len[p]+1;
        for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
        if(!p)fa[np]=1;
        else{
            int q=ch[p][c];
            if(len[p]+1==len[q])fa[np]=q;
            else{
                int nq=++cnt;len[nq]=len[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[nq]));
                fa[nq]=fa[q],fa[q]=fa[np]=nq;
                for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
            }
        }
    }
}sam;
signed main(){
    while(scanf("%s",s+1)!=EOF){
        rd(w1),rd(w2);n=strlen(s+1);
        sam.clear();int p=1,l=1;
        for(int r=1;r<=n;++r){
            f[r]=f[r-1]+w1;int c=s[r]-'a';
            while((!sam.ch[p][c]||r-l+1>l-1)&&l<=r){
                sam.extend(s[l++]-'a');
                while(p&&sam.len[sam.fa[p]]>=r-l)p=sam.fa[p];
                if(!p)p=1;
            }
            p=sam.ch[p][c];
            while(p&&sam.len[sam.fa[p]]>=r-l+1)p=sam.fa[p];
            if(!p)p=1;
            if(l<=r){
                f[r]=min(f[r],f[l-1]+w2);
            }
        }
        pt(f[n],'\n');
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xay5421/p/11231196.html