zoukankan      html  css  js  c++  java
  • HDU5470 Typewriter (后缀自动机优化dp)

    HDU-5470 Typewriter (后缀自动机优化dp)

    这个\(dp\)有两种转移

    1.\(dp[i-1]+cost[s[i]] \rightarrow dp[i]\)

    2.$ dp[j]+(i-j) \cdot A+2 \cdot B \rightarrow dp[i] $ ( $s_{j+1,i} $ 是 \(s_{1,j}\) 的一个子串)

    第一种转移不必多说

    对于第二种转移,合法的下标\(j\)一定是到\(i-1\)的一段连续区间

    设临界的下标\(j\)\(x\),找到\(S_{x,i}\)对应的状态\(st\),那么\(min\{endpos_{st}\} \leq x\)

    我们在转移的同时,不断匹配\(S_{1,i}\)对应的状态\(p\),那么\(S_{x,i}\)对应的状态就一定是\(p\)\(parent/link\)树上的一个祖先

    暴力一点的话,可以通过 树上倍增+线段树/树状数组 来实现

    #include<bits/stdc++.h>
    using namespace std;
    
    #define reg register
    typedef long long ll;
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    
    #define pb push_back
    template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
    template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
    
    char IO;
    int rd(){
        int s=0,f=0;
        while(!isdigit(IO=getchar())) if(IO=='-') f=1;
        do s=(s<<1)+(s<<3)+(IO^'0');
        while(isdigit(IO=getchar()));
        return f?-s:s;
    }
    
    const int N=2e5+10;
    
    int n,A,B;
    char S[N];
    int Cost[30];
    
    ll dp[N],temp[N];
    int fa[20][N];
    int vis[N];
    struct I_Hate_It{// 线段树
        ll s[N<<1];
        int bit;
        void Init(){
            bit=1;
            while(bit<=n+2) bit<<=1;
            rep(i,1,bit+n+1) s[i]=1e18;
        }
        void Upd(int p,ll x){
            p++;
            p+=bit,s[p]=x;
            while(p>1) p>>=1,s[p]=min(s[p<<1],s[p<<1|1]);
        }
        ll Que(int l,int r) {
            l++,r++;
            if(l==r) return s[l+bit];
            ll res=1e18;
            for(l+=bit-1,r+=bit+1;l^r^1;l>>=1,r>>=1) {
                if(~l&1) cmin(res,s[l^1]);
                if(r&1) cmin(res,s[r^1]);
            }
            return res;
        }
    }Tree;
    
    
    int trans[N][26],link[N],len[N],stcnt,lst,First[N];
    
    void Init(){
        link[0]=-1,len[0]=0;
        rep(i,0,stcnt) {
            vis[i]=0;
            rep(j,0,25) trans[i][j]=0;
        }
        lst=stcnt=0;
    }
    
    void Extend(int c) {
        int cur=++stcnt,p=lst;
        First[cur]=len[cur]=len[p]+1;
        while(~p && !trans[p][c]) trans[p][c]=cur,p=link[p];
        if(p==-1) link[cur]=0;
        else {
            int q=trans[p][c];
            if(len[q]==len[p]+1) link[cur]=q;
            else {
                int clone=++stcnt;
                memcpy(trans[clone],trans[q],104);
                First[clone]=First[q];
                len[clone]=len[p]+1,link[clone]=link[q];
                while(~p && trans[p][c]==q) trans[p][c]=clone,p=link[p];
                link[cur]=link[q]=clone;
            }
        }
        lst=cur;
    }
    
    int main(){
        rep(kase,1,rd()) {
            scanf("%s",S+1),n=strlen(S+1);
            dp[0]=0;
            Init(),Tree.Init();
            rep(i,1,n) Extend(S[i]-'a');
            rep(i,0,25) Cost[i]=rd();
            A=rd(),B=rd();
            int p=0;
            fa[0][0]=0; rep(i,1,stcnt) fa[0][i]=link[i];
            rep(i,1,18) rep(j,1,stcnt) fa[i][j]=fa[i-1][fa[i-1][j]];
            rep(i,1,n) {
                dp[i]=1e18;
                p=trans[p][S[i]-'a'];
                int now=p;
                if(now && First[now]<i-len[link[now]]) cmin(dp[i],Tree.Que(First[now],i-1));
                else {
                    drep(j,17,0) if(fa[j][now] && First[fa[j][now]]>=i-len[link[fa[j][now]]])
                        now=fa[j][now];
                    now=fa[0][now]; 
                    if(now && max(i-len[now],First[now])<i-len[link[now]]) 
                        cmin(dp[i],Tree.Que(max(i-len[now],First[now]),i-1));//倍增找到合法子串
                }
                dp[i]+=1ll*i*A+B*2;
                cmin(dp[i],dp[i-1]+Cost[S[i]-'a']);
                Tree.Upd(i,dp[i]-1ll*i*A);
            }
            printf("Case #%d: %lld\n",kase,dp[n]);
        }
    }
    
    
    
    
  • 相关阅读:
    对眼睛有利的屏幕颜色
    C++的动态联编与静态联编【转载】
    关于虚析构函数
    虚析构函数的使用(转载!)
    c/c++内存机制(转)
    delete this
    PhpStorm环境配置
    flutter之路由与导航
    flutter之Widget
    Flutter项目初步认识
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12216869.html
Copyright © 2011-2022 走看看