题意:给你n个字符串,每个字符串s[i]都有相应的花费代价cost[i]。问用这些已有的串拼出一个给定的T串的最小花费是多少。

思路:已知有n个模式串,再给出一个匹配串。很标准的一道AC自动机的题,花费最小的话也很容易想到用dp来做,dp[i]代表能拼出T[1~i]的最小花费,转移方程 dp[i]=min(dp[i],dp[i-len(s[i])]+cost[i])。但是不能直接用匹配串跑一个裸的AC自动机,这里需要用到trans指针优化,否则会卡在一组数据上。(好菜啊...学了两天的AC自动机终于把这题补掉了

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define pii pair<int,int>
#define pll pair<ll, ll>
#define pb push_back
#define X first
#define Y second
inline ll gcd(ll a, ll b) { while (b != 0) { ll c = a % b; a = b; b = c; }return a < 0 ? -a : a; }
inline ll lowbit(ll x) { return x & (-x); }
const double PI = 3.14159265358979323846;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
inline ll rd() {
    ll x = 0, f = 1; char ch = getchar();
    while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); }
    return x * f;
}
const double eps = 1e-6;
const int M = 5e5 + 10;
const int N = 5e5 + 10;
string s[N];
int n;
map<string, int>mp;
map<string, int>cnt;
//int cnt[N];
ll cc[N];
ll dp[N];
struct AC_M {
    struct Node {
        int next[26];
        int fail = 0;
        int exit = 0;
        int trans = 0;
        ll cost = 0;
    }trie[M];

    int root = 1;
    int tot = 1;

    void init() {
        for (int i = 1; i <= tot; i++) {
            memset(trie[i].next, 0, sizeof trie[i].next);
            trie[i].exit = 0;
            //trie[i].num = 0;
            trie[i].fail = 0;
        }
        tot = 1;
    }

    void insert(string s, ll cc) {
        int len = s.length();
        int p = root;
        for (int i = 0; i < len; i++) {
            int x = s[i] - 'a';
            if (trie[p].next[x] == 0)trie[p].next[x] = ++tot;
            p = trie[p].next[x];
        }
        trie[p].exit = len;
        //trie[p].num = 1;
        if (trie[p].cost == 0)trie[p].cost = cc;
        else trie[p].cost = min(trie[p].cost, cc);
    }

    void build() {
        for (int i = 1; i <= n; i++) {
            insert(s[i], cc[i]);
        }
        queue<int>q;
        for (int i = 0; i < 26; i++) {
            if (trie[root].next[i]) {
                trie[trie[root].next[i]].fail = root;
                trie[trie[root].next[i]].trans = root;
                q.push(trie[root].next[i]);
            }
            else {
                trie[root].next[i] = root;
            }
        }

        while (q.size()) {
            int x = q.front(); q.pop();
            for (int i = 0; i < 26; i++) {
                int y = trie[x].next[i];
                int fafail = trie[x].fail;
                if (y) {
                    trie[y].fail = trie[fafail].next[i];
                    q.push(y);
                    int q = trie[y].fail;
                    if (trie[q].exit == 0) {
                        trie[y].trans = trie[q].trans;
                    }
                    else {
                        trie[y].trans = q;
                    }
                }
                else {
                    trie[x].next[i] = trie[fafail].next[i];
                }
            }
        }
    }

    void query(string T) {
        int len = T.length();
        int p = root;
        int ans = 0;
        for (int i = 1; i <= len; i++) {
            int x = T[i - 1] - 'a';
            p = trie[p].next[x];
            for (int t = p; t; t = trie[t].trans) {
                if (trie[t].cost) {
                    //cnt[T.substr(i - trie[t].exit + 1, trie[t].exit)]++;
                    if (i - trie[t].exit < 0)continue;
                    dp[i] = min(dp[i], dp[i - trie[t].exit] + trie[t].cost);
                }
            }
        }
    }
}_AC;

int main() {
    n = rd();
    for (int i = 1; i <= n; i++) {
        cin >> s[i];
        cc[i] = rd();
        //mp[s[i]] = i;
    }
    _AC.init();
    _AC.build();
    string T; cin >> T;
    memset(dp, INF, sizeof dp);
    dp[0] = 0;
    _AC.query(T);
    //for (int i = 1; i <= n; i++) {
    //  cout << cnt[s[i]] << endl;
    //}
    if (dp[T.length()] == INF)cout << -1 << endl;
    else cout << dp[T.length()] << endl;
}