Hari Merdeka UVALive - 6806

本文介绍了一种结合AC自动机和动态规划的方法,用于解决特定模式匹配问题。通过构建AC自动机并利用其fail路径上的状态转移进行背包DP,实现了在给定字符串集合中寻找最优匹配的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用给的模式串build一个ac自动机
然后在fail树上做一个背包dp
dp[i][j]表示第i个状态下花费了 j 获得的最大价值

(顺便升级了一下原来的ac自动机模版)

#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <queue>
#include <cstdio>
#include <map>
#include <set>
#include <utility>
#include <stack>
#include <cstring>
#include <cmath>
#include <vector>
#include <ctime>
#include <bitset>
using namespace std;
#define pb push_back
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d%d",&n,&m)
#define sddd(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define sld(n) scanf("%lld",&n)
#define sldd(n,m) scanf("%lld%lld",&n,&m)
#define slddd(n,m,k) scanf("%lld%lld%lld",&n,&m,&k)
#define sf(n) scanf("%lf",&n)
#define sff(n,m) scanf("%lf%lf",&n,&m)
#define sfff(n,m,k) scanf("%lf%lf%lf",&n,&m,&k)
#define ss(str) scanf("%s",str)
#define ansn() printf("%d\n",ans)
#define lansn() printf("%lld\n",ans)
#define r0(i,n) for(int i=0;i<(n);++i)
#define r1(i,e) for(int i=1;i<=e;++i)
#define rn(i,e) for(int i=e;i>=1;--i)
#define mst(abc,bca) memset(abc,bca,sizeof abc)
#define lowbit(a) (a&(-a))
#define all(a) a.begin(),a.end()
#define pii pair<int,int>
#define pll pair<long long,long long>
#define mp(aa,bb) make_pair(aa,bb)
#define lrt rt<<1
#define rrt rt<<1|1
#define X first
#define Y second
#define PI (acos(-1.0))
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
//const ll mod = 1000000007 ;
const double eps=1e-9;
const int inf=0x3f3f3f3f;
//const ll infl = 100000000000000000;//1e17
const int maxn=  1e5+20;
const int maxm = 5e2+20;
//muv[i]=(p-(p/i))*muv[p%i]%p;
int in(int &ret) {
    char c;
    int sgn ;
    if(c=getchar(),c==EOF)return -1;
    while(c!='-'&&(c<'0'||c>'9'))c=getchar();
    sgn = (c=='-')?-1:1;
    ret = (c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9')ret = ret*10+(c-'0');
    ret *=sgn;
    return 1;
}

int ch[maxn][26];
int val[maxn],f[maxn],last[maxn];
int dp[maxn][222];
int sz;
void trie() {
    sz=1;
    mst(ch[0],-1);
}
void triein(char *s,int v) {
    int u=0,n=strlen(s);
    for(int i=0; i<n; ++i) {
        int c=s[i]-'A';
        if(ch[u][c]==-1) {
            mst(ch[sz],-1);
            val[sz]=0;
            ch[u][c]=sz++;
        }
        u=ch[u][c];
    }
    val[u]+=v;
}
void build() {
    f[0]=0;
    queue<int>q;
    for(int c=0; c<26; ++c) {
        int u=ch[0][c];
        if(u==-1) {
            ch[0][c] = 0;
            continue;
        }
        q.push(u);
        f[u]=0;
//        last[u]=0;
    }
    while(!q.empty()) {
        int r=q.front();
        q.pop();
        for(int c=0; c<26; ++c) {
            int u=ch[r][c];
            if(u==-1) {
                ch[r][c] = ch[f[r]][c];
                continue;
            }
            q.push(u);
            int v=f[r];
//            while(v&&!ch[v][c])v=f[v];
            f[u]=ch[v][c];
//            last[u]= val[ f[u] ] ? f[u] : last[f[u]];
            val[u] += val[f[u]];
        }
    }
}
vector<pii>v;
char s[maxn];
int k;
int n,m;
int ans = 0;
void cal() {
    mst(dp,-1);
    dp[0][0] = 0;
    ans = 0;
    for(int i=0; i<=k; ++i) {
        for(int j=0; j<sz; ++j) {
            ans = max(ans,dp[j][i]);
            if(~dp[j][i])
                for(int w = 0; w<n; ++w) {
                    int u = v[w].X ;
                    int c = v[w].Y ;
                    int nt = ch[j][u];
                    if(nt>=0&&nt<sz&&i+c<=k)
                    dp[nt][i+c] = max(dp[nt][i+c] , dp[j][i] + val[nt]);
                }
        }
    }
}
int main() {
#ifdef LOCAL
    freopen("input.txt","r",stdin);
//    freopen("output.txt","w",stdout);
#endif // LOCAL


    int t;
    sd(t);
    r1(cas,t) {
        printf("Case #%d: ",cas);
        trie();
        v.clear();
        sddd(n,m,k);
        r1(i,n) {
            ss(s);
            int x = s[0] - 'A';
            int y;
            sd(y);
            v.pb(mp(x,y));
        }
        while(m--) {
            ss(s);
            int x;
            sd(x);
            triein(s,x);
        }
        build();
        cal();
        ansn();

    }


    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值