2020 camp day2 -k

题面

7-11 2K. 破忒头的匿名信

破忒头想要写一封匿名信来做坏事,由于他不想被认出自己的笔迹,因此他想要雇佣萨博来帮他写这封信。萨博按照这样的标准来收费:他的词典里有N个单词,第i个单词的单价是p​i​​。如果你提供一个长度为M的序列,,那么你需要支付∑​i=1​M​​p​a​i​​​​的金钱,而萨博会依次往信里写上。破忒头希望支付最少的金钱,让萨博写的内容恰好为他想要的信件内容T。请你告诉破忒头,最少需要付多少钱,能让萨博写出他想要的匿名信,或者告诉他这是不可能做到的。

输入格式:

对于每组测试数据,第一行包含一个正整数N,表示萨博词典里的单词个数(1)。接下来的N行描述词典里的每个单词,第i行包含一个字符串Si​​和这个字符串的单价pi​​(1)。接下来一行包含破忒头想要的信件内容T(1)。保证Si​​和T都仅包含小写字母,且Si​​的总长度不超过5。

输出格式

如果有可能让萨博写出破忒头想要的信件内容,那么输出一个正整数,表示最小需要付出的代价。否则,输出-1。

输入样例:

4
ab 5
cd 10
abc 100
d 1
abcd
 
1
ab 1
abc
 

输出样例:

15
 
-1

作者: 2020,Winter,Day2
单位: 东北大学秦皇岛分校
时间限制: 5000 ms
内存限制: 256 MB
代码长度限制: 16 KB
 

题解

基本的ac自动机构造 + DAG上dp

注意insert时,不像以往,对于重复字串,我们只更新其价格使其价格最低,即每个结尾至多只有一个字符串结尾,并记录下这个字符串的长度(深度)。

对于query,不再查询有多少个字串,直接开始dp,有点像01背包,但有所不同。

其他都是细节。

代码如下

#include<cstdio>
#include<cstring>
#include<algorithm>

#define RE register
#define FOR(i,a,b) for(RE int i=a;i<=b;++i)
#define ROF(i,a,b) for(int i=a;i>=b;--i)
#define ll long long 
#define sc(x) scanf("%d",&x)
#define ss(s) scanf("%s",s)

using namespace std;

const int MAXN = 5e5 + 10;
const int inf = 0x3f3f3f3f;
const int C = 'a';
const int M = 26;

int n, len, cost;
char s[MAXN];
ll d[MAXN];

struct ac
{
    int trie[MAXN][M], fail[MAXN], lenth[MAXN], vis[MAXN];
    ll val[MAXN];
    int q[MAXN], tot;

    void insert(char* s, ll v)
    {
        int p = 0;
        for (RE int i = 0; s[i]; ++i)
        {
            int ch = s[i] - C;
            if (!trie[p][ch])trie[p][ch] = ++tot; 
            p = trie[p][ch];
            lenth[p] = i + 1;
        }
        if (val[p])val[p] = min(val[p], v);
        else val[p] = v;
    }

    void build()
    {
        int head = 0, tail = -1;
        FOR(i, 0, M - 1)
            if (trie[0][i])
                q[++tail] = trie[0][i];
        while (head <= tail)
        {
            int p = q[head++];
            FOR(i, 0, M - 1)
                if (trie[p][i])
                    fail[trie[p][i]] = trie[fail[p]][i],
                    q[++tail] = trie[p][i];
                else trie[p][i] = trie[fail[p]][i];
        }
    }

    void  query(char* s)
    {
        int p = 0;
        for (RE int i = 0; s[i]; ++i)
        {
            p = trie[p][s[i] - C];
            for (RE int tmp = p; tmp; tmp = fail[tmp])
            {
                if (vis[i - lenth[tmp] + 1] && val[tmp])
                {
                    d[i + 1] = min(d[i + 1], d[i - lenth[tmp] + 1] + val[tmp]);
                    vis[i + 1] = 1;
                }
            }
        }
    }
}a;

int main()
{
    sc(n);
    FOR(i, 1, n)
    {
        ss(s); sc(cost);
        a.insert(s, cost);
    }
    a.build();ss(s);
    len = strlen(s);
    a.vis[0] = 1;
    for (RE int i = 1; i <= len; ++i)
        d[i] = 1ll * inf * inf;
    a.query(s);
    if (!a.vis[len])puts("-1");
    else printf("%lld
", d[len]);
    return 0;
}

  

 
原文地址:https://www.cnblogs.com/2aptx4869/p/12194209.html