2020 CCPC Wannafly Winter Camp Day2 K题 破忒头的匿名信(AC自动机+dp)

这题要看出dp更新的方法,因为我们有很多字符串,而最后的串可以随意组装而来

因此dp状态设计为f[i]到i的最小代价,这也一直往下跳,更新的时候更新fail链上的所有答案,因为这些是可以成为他的后缀更新过来的,这也就枚举到了所有的情况

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+10;
struct node{
    int cnt;
    node * nxt[27];
    node * fail;
    vector<node *> num;
}*rt;
node pool[N];
int n,m,idx;
ll val[N];
int num;
int st[N];
ll f[N];
void insert(string s,int x){
    node *p=rt;
    int i;
    for(i=0;i<s.size();i++){
        int sign=s[i]-'a';
        if(p->nxt[sign]==NULL){
            p->nxt[sign]=pool+(++idx);
            p->nxt[sign]->cnt=++num;
        }
        p=p->nxt[sign];
        if(i==(int)s.size()-1){
            if(!val[p->cnt])
                val[p->cnt]=x;
            else
            val[p->cnt]=min(val[p->cnt],1ll*x);
            st[p->cnt]=(int)s.size();
        }
    }
}
void build(){
    int i;
    queue<node *> q;
    rt->fail=rt;
    for(i=0;i<26;i++){
        if(rt->nxt[i]){
            rt->nxt[i]->fail=rt;
            rt->num.push_back(rt->nxt[i]);
            q.push(rt->nxt[i]);
        }
        else{
            rt->nxt[i]=rt;
            rt->nxt[i]->fail=rt;
        }
    }
    while(q.size()){
        auto t=q.front();
        q.pop();
        for(i=0;i<26;i++){
            if(t->nxt[i]){
                t->nxt[i]->fail=t->fail->nxt[i];
                t->fail->nxt[i]->num.push_back(t->nxt[i]);
                q.push(t->nxt[i]);
            }
            else{
                t->nxt[i]=t->fail->nxt[i];
            }
        }
    }
}
void dfs(string s){
    int len=(int)s.size();
    int i,j;
    node *p=rt;
    for(i=0;i<len;i++){
        p=p->nxt[s[i]-'a'];
        node *x=p;
        while(x!=rt){
            if(st[x->cnt]){
                f[i+1]=min(f[i+1],f[i+1-st[x->cnt]]+val[x->cnt]);
            }
            x=x->fail;
        }
    }
    if(f[len]==1e18){
        cout<<-1<<endl;
    }
    else{
        cout<<f[len]<<endl;
    }
}
int main(){
    ios::sync_with_stdio(false);
    rt=pool;
    rt->cnt=0;
    int i,j;
    cin>>n;
    for(i=1;i<=n;i++){
        string s;
        int x;
        cin>>s>>x;
        insert(s,x);
    }
    build();
    string s;
    cin>>s;
    for(int i=0;i<=(int)s.size();i++)
        f[i]=1e18;
    f[0]=0;
    dfs(s);
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/14123344.html