HDU-5470 Typewriter (後綴自動機優化dp)

HDU-5470 Typewriter (後綴自動機優化dp)

這個\(dp\)有兩種轉移c++

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

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

第一種轉移沒必要多說優化

對於第二種轉移,合法的下標\(j\)必定是到\(i-1\)的一段連續區間spa

設臨界的下標\(j\)\(x\),找到\(S_{x,i}\)對應的狀態\(st\),那麼\(min\{endpos_{st}\} \leq x\)code

咱們在轉移的同時,不斷委會\(S_{1,i}\)對應的狀態\(p\),那麼\(S_{x,i}\)對應的狀態就必定是\(p\)\(parent/link\)樹上的一個祖先get

暴力一點的話,能夠經過 樹上倍增+線段樹/樹狀數組 來實現it

#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]);
    }
}
相關文章
相關標籤/搜索