Codeforces 433E

自动机上的数位dp
dp[i][j][k] 表示将要考虑到第i个位置,目前走到自动机第j号节点,目前总的价值k,的情况总数

HDU 2457
/f[u]=r,r������u�ĺ�׺��
/last[u]=r,r������u�ĺ�׺�У�������һ������
ÿ����һ����ĸ��״̬ת��һ��
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
typedef __int64 LL;
const int N=220;
const int inf=1<<25;
const int MN=220*220+100;
const int SZ=30;
const int mod=1e9+7;
int ch[MN][SZ];int val[MN];
int sz,tot;
void init(){tot=1;sz=26;memset(ch[0],0,sizeof(ch[0]));val[0]=0;}
void Ins(int ss[],int n,int v){
    int u=0;
    for(int i=0;i<n;i++){
        int c=ss[i];
        if(!ch[u][c]){
            memset(ch[tot],0,sizeof(ch[tot]));val[tot]=0;
            ch[u][c]=tot++;
        }
        u=ch[u][c];
        //printf("%d ",u);
    }//printf("\n");
    val[u]+=v;
}
int f[MN],last[MN];
int getFail(){
    queue<int> qq;
    f[0]=0;last[0]=0;
    for(int c=0;c<sz;c++){
        int u=ch[0][c];
        if(u){f[u]=0;last[u]=0;qq.push(u);}
    }
    while(!qq.empty()){
        int r=qq.front();qq.pop();
        for(int c=0;c<sz;c++){
            int u=ch[r][c];
            if(!u){
                ch[r][c]=ch[f[r]][c];continue;
            }
            qq.push(u);
            f[u]=ch[f[r]][c];
            last[u]=val[f[u]]?f[u]:last[f[u]];
            val[u]+=val[f[u]];
        }
    }
}

int l,ll[N],r,rr[N];int n,m,k;
LL dp[210][420][520];
int a,aa[N],v;
LL dfs(int h,int s,int now,bool flag, bool zero){
    now -= val[s];
    if(now < 0) return 0;
    if(h==r) {
        //cout << sum << " " << now << endl;
        return 1;
    }
    if(!flag && !zero && dp[h][s][now] != -1) return dp[h][s][now];

    LL res = 0;
    if(zero){
        res += dfs(h+1,s,now,flag && rr[h]==0,true);
        res %= mod;
    }else{
        res += dfs(h+1,ch[s][0],now,flag && rr[h]==0,false);
        res %= mod;
    }

    int up = flag?rr[h]:m-1;
    for(int i=1;i<=up;i++){
        res += dfs(h+1,ch[s][i],now,flag && i==up,false);
        res %= mod;
    }

    if(!flag && !zero) dp[h][s][now] = res;
    return res;
}
int main(){
    #ifdef DouBi
    freopen("in.cpp","r",stdin);
    #endif // DouBi
    while(scanf("%d%d%d",&n,&m,&k)!=EOF){
        scanf("%d",&l);for(int i=0;i<l;i++)scanf("%d",&ll[i]);
        scanf("%d",&r);for(int i=0;i<r;i++)scanf("%d",&rr[i]);
        for(int i=1;i<=l;i++){
            ll[r-i]=ll[l-i];
        }
        for(int i=0;i<r-l;i++)ll[i]=0;
        for(int i=r-1;i>=0;i--){
            if(ll[i]){
                ll[i]--;
                for(int j=i+1;j<r;j++){
                    ll[j]=m-1;
                }
                break;
            }
        }
        init();
        for(int i=0;i<n;i++){
            scanf("%d",&a);
            for(int j=0;j<a;j++){
                scanf("%d",&aa[j]);
            }
            scanf("%d",&v);
            Ins(aa,a,v);
        }
        getFail();
        LL ans=0;
        memset(dp,-1,sizeof(dp));
        ans=dfs(0,0,k,1,1);
        //printf("%I64d ",ans);
        for(int i=0;i<r;i++){
            rr[i]=ll[i];
        }
        memset(dp,-1,sizeof(dp));
        ans-=dfs(0,0,k,1,1);
        printf("%I64d\n",(ans%mod+mod)%mod);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值