• K 破忒头的匿名信(ac自动机+小dp)


    题:https://ac.nowcoder.com/acm/contest/4010/K

    题意:用一些模式串凑成一个目标串,每个模式串有消耗,问组合的最小消耗,或不能组成输出-1;

    分析:典型的AC自动机处理后在跳fail的过程中进行操作,这里操作就是dp计算最小。用dp[i]表示长串前ii位的最小代价,若有一个单词s是长串的前ii项的后缀,那么可以用dp[i−len(s)]+val(s)转移到dp[i]

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll INF=1e18;
    const int M=5e5+6;
    int trie[M][26],fail[M],cnt;
    ll val[M],dp[M],deep[M];
    void insert(string s,ll v){
        int root=0,len=s.size();
        for(int i=0;i<len;i++){
            if(!trie[root][s[i]-'a'])
                trie[root][s[i]-'a']=++cnt;
            root=trie[root][s[i]-'a'];
        }
        val[root]=min(val[root],v);
        deep[root]=len;
    }
    void getfail(){
        queue<int>que;
        while(!que.empty())
            que.pop();
        for(int i=0;i<26;i++)
            if(trie[0][i]){
                fail[trie[0][i]]=0;
                que.push(trie[0][i]);
            }
        while(!que.empty()){
            int now=que.front();
            que.pop();
            for(int i=0;i<26;i++){
                if(trie[now][i]){
                    fail[trie[now][i]]=trie[fail[now]][i];
                    que.push(trie[now][i]);
                }
                else
                    trie[now][i]=trie[fail[now]][i];
            }
        }
    }
    ll query(string s){
        int now=0,len=s.size();
        for(int i=0;i<len;i++){
            now=trie[now][s[i]-'a'];
            for(int j=now;j;j=fail[j]){
                if(deep[j])
                    dp[i+1]=min(dp[i+1],dp[i+1-deep[j]]+val[j]);
            }
        }
        if(dp[len]>=INF)
            return -1;
        return dp[len];
    }
    void init(){
        for(int i=0;i<M;i++)
            dp[i]=val[i]=INF;
        dp[0]=val[0]=0;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0);
        init();
        int n;
        string s;
        cin>>n;
        for(int i=1;i<=n;i++){
            ll v;
            cin>>s>>v;
            insert(s,v);
        }
        fail[0]=0;
        getfail();
        cin>>s;
        cout<<query(s);
        return 0;
    }
    View Code
  • 相关阅读:
    SpringBoot之旅第三篇-日志
    SpringBoot之旅第二篇-配置
    SpringBoot之旅第一篇-初探
    394. 字符串解码
    1190. 反转每对括号间的子串
    921. 使括号有效的最少添加
    Leetcode 1171. 从链表中删去总和值为零的连续节点
    设计模式之过滤器模式——Java语言描述
    MySQL查询执行的基础
    设计模式之桥接模式——Java语言描述
  • 原文地址:https://www.cnblogs.com/starve/p/12258122.html
Copyright © 2020-2023  润新知