• HDU-6583 Typewriter 后缀自动机+dp


    HDU-6583 Typewriter

    题意

    你有两种打字模式:

    • 花费(p)元在字符串结尾增加一个任意的字符。
    • 花费(q)元在字符串结尾增加一个之前已经出现过的子串。

    给一个字符串(S),问打完这个字符串所需的最小花费为多少。

    (|S|le 2cdot 10^5)

    分析

    (dp[i])为打完前(i)个字符所需的最小花费,按照第一种打字方式有(dp[i]=min(dp[i],dp[i-1]+p))

    按照第二种打字方式, 在后缀自动机插入前(i)个字符后,每次找到一个最远的位置(j),且(s[1;j])在后缀自动机上能匹配到的最长后缀(len)大于(j-i+1),更新(dp[j]=min(dp[j],dp[i]+q))

    最后答案即为(dp[n])

    Code

    #include<bits/stdc++.h>
    #define rep(i,x,n) for(int i=x;i<=n;i++)
    #define per(i,n,x) for(int i=n;i>=x;i--)
    #define sz(a) int(a.size())
    #define rson mid+1,r,p<<1|1
    #define pii pair<int,int>
    #define lson l,mid,p<<1
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define se second
    #define fi first
    using namespace std;
    const double eps=1e-8;
    const int mod=1e9+7;
    const int N=4e5+10;
    const ll inf=1e18;
    int T,n;
    ll p,q;
    char s[N];
    struct SAM{
        int last,cnt;int ch[N][26],fa[N],len[N];
        ll dp[N];
        int newnode(){
            ++cnt;
            for(int i=0;i<26;i++) ch[cnt][i]=0;
            return cnt;
        }
        void insert(int c){
            int p=last,np=newnode();last=np;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[q]==len[p]+1) fa[np]=q;
                else{
                    int nq=newnode();len[nq]=len[p]+1;
                    memcpy(ch[nq],ch[q],sizeof ch[q]);
                    fa[nq]=fa[q],fa[q]=fa[np]=nq;
                    for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
                }
            }
        }
        void init(){
            last=cnt=1;
            for(int i=0;i<26;i++) ch[cnt][i]=0;
        }
        ll solve(){
            rep(i,1,n) dp[i]=inf;
            ll ans=0;
            int u=1,l=0;
            for(int i=1,j=1;i<=n;i++){
                insert(s[i]-'a');
                while(j<=n){
                    while(!ch[u][s[j]-'a']&&u!=1&&len[fa[u]]+i>=j-1) u=fa[u],l=len[u];
                    if(ch[u][s[j]-'a']){
                        u=ch[u][s[j]-'a'],l++;
                        j++;
                    }else break;
                }
                dp[i]=min(dp[i],dp[i-1]+p);
                if(j-1>i) dp[j-1]=min(dp[j-1],dp[i]+q);
            }
            return dp[n];
        }
    }sam;
    int main(){
        while(~scanf("%s",s+1)){
            scanf("%lld%lld",&p,&q);
            sam.init();
            n=strlen(s+1);
            printf("%lld
    ",sam.solve());
        }
        return 0;
    }
    
  • 相关阅读:
    【转】web测试容易被遗忘的地方
    212
    将博客搬至CSDN
    关于Navicat连接虚拟机windows virsual pc 的mysql
    Java匿名内部类继承类和实现接口
    [转]文本输入框特效大集合
    jquery操作select
    HashMap和Hashtable的区别
    Struts2+Spring+hibernate最新版本官方下载地址
    Java
  • 原文地址:https://www.cnblogs.com/xyq0220/p/13931494.html
Copyright © 2020-2023  润新知