zoukankan      html  css  js  c++  java
  • zoj3494 ac自动机+数位dp

    题目链接:zoj3494

    题解:把给的串建ac自动机,然后得到的bcd[i][j],bcd[i][j]表示在AC自动机上的状态i,后面加入j会转移的状态,-1表示不能加

    然后数位dp,dp[i][j]表示取到第i位状态为j后面的数字随便取的方案数,这里是记忆化。

    #include<bits/stdc++.h>
    #include<set>
    #include<cstdio>
    #include<iomanip>
    #include<iostream>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #define pb push_back
    #define mk make_pair
    #define ll long long
    #define fi first
    #define se second
    #define PI 3.14159265
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    #define eps 1e-7
    #define pii pair<int,int>
    #define pll pair<ll,ll>
    typedef unsigned long long ull;
    const int mod=1000000009;
    const ll inf=0x3f3f3f3f3f3f3f;
    const int N=2e3+100;
    using namespace std;
    char s[300];
    int n;
    struct ac_auto
    {
        int nxt[N][2],ed[N],fail[N],cn,rt;
        ac_auto(){}
        void init(){
            memset(nxt,-1,sizeof(nxt));
            memset(ed,0,sizeof(ed));
            memset(fail,-1,sizeof(fail));
            cn=0;
            rt=new_node();
        }
        int new_node()
        {
            return cn++;
        }
        void insert(char *s)
        {
            int len=strlen(s);
            int p=rt;
            for(int i=0;i<len;i++)
            {
                int x=s[i]-'0';
                if(nxt[p][x]==-1)nxt[p][x]=new_node();
                p=nxt[p][x];
            }
            ed[p]=1;
        }
         void build()
        {
            queue<int>q;
            fail[rt] = rt;
            for(int i = 0;i < 2;i++)
                if(nxt[rt][i] == -1)
                    nxt[rt][i] = rt;
                else
                {
                    fail[nxt[rt][i]] = rt;
                    q.push(nxt[rt][i]);
                }
                while(!q.empty())
                {
                    int now = q.front();
                    q.pop();
                    if(ed[fail[now]])ed[now] = true;
                    for(int i = 0;i < 2;i++)
                        if(nxt[now][i] == -1)
                            nxt[now][i] = nxt[fail[now]][i];
                        else
                        {
                            fail[nxt[now][i]] = nxt[fail[now]][i];
                            q.push(nxt[now][i]);
                        }
                }
        }
    }ac;
    int bcd[N][10];
    int judge(int x,int y)
    {
        if(ac.ed[x])return -1;
        for(int i=3;i>=0;i--)
        {
            if(ac.ed[ac.nxt[x][(y>>i)&1]])return -1;
            x=ac.nxt[x][(y>>i)&1];
        }
        return x;
    }
    void slove()
    {
        for(int i=0;i<ac.cn;i++)
        {
            for(int j=0;j<10;j++)
            {
               bcd[i][j]=judge(i,j);
            }
        }
    }
    ll dp[210][N];
    int bit[300];
    ll dfs(int p,int s,int flag,int z)//p第几位,s当前的状态,flag是否已经有高位小于s,前面是否有非0值
    {
        if(p==-1)return 1;
        if(!flag&&dp[p][s]!=-1)return dp[p][s];
        ll ans=0;
        if(z)
        {
            ans+=dfs(p-1,s,0,1);
            ans%=mod;
        }
        else
        {
            if(bcd[s][0]!=-1)ans+=dfs(p-1,bcd[s][0],flag&&bit[p]==0,0);
            ans%=mod;
        }
        int lim=(flag?bit[p]:9);
        for(int i=1;i<=lim;i++)
        {
            if(bcd[s][i]!=-1)ans+=dfs(p-1,bcd[s][i],flag&&i==bit[p],0);
            ans%=mod;
        }
        if(!flag&&!z)dp[p][s]=ans;
        return ans;
    }
    ll get(char *s)
    {
        int len=strlen(s);
        for(int i=0;i<len;i++)
        {
            bit[i]=s[len-1-i]-'0';
        }
        return dfs(len-1,0,1,1);
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            memset(dp,-1,sizeof(dp));
            ac.init();
           scanf("%d",&n);
            for(int i=0;i<n;i++)
            {
                scanf("%s",s);
                ac.insert(s);
            }
            ac.build();
            slove();
            scanf("%s",s);
            int len=strlen(s);
            for(int i=len-1;i>=0;i--)
            {
                if(s[i]>'0')
                {
                    s[i]--;break;
                }
                else s[i]='9';
            }
            ll ans=0;
            ans-=get(s);
            ans%=mod;
            scanf("%s",s);
            ans+=get(s);
            ans%=mod;
            if(ans<0)ans+=mod;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    /*
    1
    2 1 2
    1 2
    1 1 1
    2 1 2
    */
  • 相关阅读:
    linux 树型显示文件 tree ls tree 命令
    Linux常用命令大全
    My kingdom for a good timer! 规格严格
    org.dom4j.DocumentException: no protocol 规格严格
    利用GetObject("WinMgmts:")获取系统信息 规格严格
    给力URL 规格严格
    几个Servlet小Sample网站 规格严格
    使用SQL PLUS生成报表 规格严格
    High Resolution Timer in Java 5 规格严格
    GC调优文章精选:逐步添加 规格严格
  • 原文地址:https://www.cnblogs.com/lhclqslove/p/10718750.html
Copyright © 2011-2022 走看看