ZOJ 3494 BCD Code - AC自动机 - 数位dp

没有传送门
没有题目大意
AC自动机维护数位dp模板题
从一位神犇那里get到了一中不特判前导0姿势
我真是愚蠢晚期
真是愚蠢晚期
愚蠢晚期
晚期

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#define mod 1000000009
#define N 110
#define LEN 210
#define TN 2010
#define toi(c) (c-'0')
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
struct ac_node{
    int ch[2],fail;bool val;
}t[TN];int ac_node_cnt;
char A[LEN],B[LEN];bool ban[TN];
int a[LEN],b[LEN],dp[LEN][TN][2];
int can[TN][15],f[LEN][TN];
inline int new_ac_node()
{
    int x=++ac_node_cnt;t[x].fail=0,t[x].val=0;
    return t[x].ch[0]=t[x].ch[1]=0,ac_node_cnt;
}
inline int solve(int x,int a)
{
    if(ban[x]) return 0;
    for(int i=3;i>=0;i--)
    {
        x=t[x].ch[(a&(1<<i))>>i];
        if(ban[x]) return 0;
    }
    return x;
}
inline int get_can(int m)
{
    for(int i=1;i<=m;i++)
        for(int j=0;j<=9;j++)
            can[i][j]=solve(i,j);
    return 0;
}
inline int init_f(int n)
{
    int m=ac_node_cnt;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            f[i][j]=0;
    for(int i=1,y;i<=9;i++)
        if((y=can[1][i])) f[1][y]++;
    for(int i=1;i<n;i++)
        for(int j=1;j<=m;j++)
            if(!ban[j]&&f[i][j])
                for(int k=0,y;k<=9;k++)
                    if((y=can[j][k]))
                        (f[i+1][y]+=f[i][j])%=mod;
    return 0;
}
inline int get_ans(int *a,int n)
{
//  for(int i=1;i<=n;i++) cout<<a[i];cout<<endl;
    if(!n) return 0;
    int m=ac_node_cnt,ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) dp[i][j][0]=dp[i][j][1]=0;
    for(int i=1,y;i<=a[1];i++)
        if((y=can[1][i]))
            dp[1][y][i==a[1]]++;
    for(int i=1,y;i<n;i++)
        for(int x=1;x<=m;x++)
            if(!ban[x]) for(int j=0;j<=9;j++)
                if((y=can[x][j]))
                {
                    if(dp[i][x][0]) (dp[i+1][y][0]+=dp[i][x][0])%=mod;//,debug(i)sp,debug(x)sp,debug(i+1)sp,debug(y)ln;
                    if(dp[i][x][1]&&j<=a[i+1]) (dp[i+1][y][j==a[i+1]]+=dp[i][x][1])%=mod;//,debug(i)sp,debug(x)sp,debug(i+1)sp,debug(y)sp,debug((j==a[i+1]))ln;
                }
/*  for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            debug(i)sp,debug(j)sp,debug(dp[i][j][0])sp,debug(dp[i][j][1])ln;*/
    for(int i=1;i<=m;i++)
        if(!ban[i]) (ans+=dp[n][i][0])%=mod,(ans+=dp[n][i][1])%=mod;
/*  for(int i=1;i<n;i++)
        for(int j=1;j<=m;j++)
            debug(i)sp,debug(j)sp,debug(f[i][j])ln;*/
    for(int i=1;i<n;i++)
        for(int j=1;j<=m;j++)
            if(!ban[j]) (ans+=f[i][j])%=mod;
    return ans;
}
inline int insert_ac(int rt,char *s,int n)
{
    int x=rt;
    for(int i=1;i<=n;i++)
    {
        int c=toi(s[i]);
        if(!t[x].ch[c]) t[x].ch[c]=new_ac_node();
        x=t[x].ch[c];
    }
    t[x].val=true;return 0;
}
queue<int> q;
struct edges{
    int to,pre;
}e[TN<<1];int etop,h[TN];
inline int add_edge(int u,int v)
{
    return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop;
}
inline int get_fail(int rt)
{
    while(!q.empty()) q.pop();
    for(int i=0;i<=1;i++)
    {
        int &x=t[rt].ch[i];
        if(x) t[x].fail=rt,q.push(x),add_edge(rt,x);
        else x=rt;
    }
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=0;i<=1;i++)
        {
            int &y=t[x].ch[i],f=t[x].fail,c=t[f].ch[i];
            if(y) t[y].fail=c,q.push(y),add_edge(c,y);
            else y=c;
        }
    }
/*  for(int i=1;i<=ac_node_cnt;i++)
        debug(i)sp,debug(t[i].ch[0])sp,debug(t[i].ch[1])ln;*/
    return 0;
}
inline int get_ban(int x,bool flag)
{
    for(int i=h[x];i;i=e[i].pre)
        get_ban(e[i].to,flag|t[e[i].to].val);
    return ban[x]=flag;
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int x,n,al,bl,rt;scanf("%d",&n);
        ac_node_cnt=0,rt=new_ac_node();
        for(int i=1;i<=n;i++)
            scanf("%s",A+1),insert_ac(rt,A,(int)strlen(A+1));
        memset(h,0,sizeof(h)),etop=0;
        get_fail(rt),get_ban(rt,false),scanf("%s%s",A+1,B+1);
        al=(int)strlen(A+1),bl=(int)strlen(B+1);
        for(int i=1;i<=al;i++) a[i]=A[i]-'0';
        for(int i=1;i<=bl;i++) b[i]=B[i]-'0';
        a[x=al]--;while(a[x]<0) a[x]+=10,a[--x]--;
        if(!a[1])
        {
            for(int i=2;i<=al;i++) a[i-1]=a[i];
            al--;
        }
        get_can(ac_node_cnt),init_f(max(al,bl));
        printf("%d\n",(get_ans(b,bl)-get_ans(a,al)+mod)%mod);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值