zoukankan      html  css  js  c++  java
  • ZOJ 3494 (AC自动机+数位DP)

    题意:给n个01字符串,求区间[x , y]中有多少个数写成BCD码后不包含以上01串。

    分析:先用01字符串建立AC自动机(注意标记危险结点),然后DP。dp[i][s]表示扫描前i位后有多少个数会到达自动机的结点s.

    注意:

    1.前导0的问题:不能转化成二进制在数位dp(否则处理不了前导0),安十进制进行数位dp!

    2.d[u][sub][zero]的sub是从n->0,不是从0->n(sub表示还剩几位)    Orz。。。

    //#pragma comment(linker, "/STACK:102400000")
    #include<cstdlib>
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<list>
    #include<queue>
    #include<stack>
    #include<vector>
    #define tree int o,int l,int r
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define lo o<<1
    #define ro o<<1|1
    #define pb push_back
    #define mp make_pair
    #define ULL unsigned long long
    #define LL long long
    #define inf 0x7fffffff
    #define eps 1e-7
    #define N 2009
    #define M 2
    #define mod 1000000009
    using namespace std;
    int m,n,T,t,x,y,u;
    int ch[N][M],v[N],sz;
    int f[N],last[N],len;
    char str[29],a[209],b[209],*s;
    int d[N][809][2];
    char tr[10][5]={"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001"};
    void init()
    {
        sz=1;
        memset(ch[0],0,sizeof(ch[0]));
        memset(v,0,sizeof(v));
        memset(last,0,sizeof(last));
        memset(d,-1,sizeof(d));
    }
    int idx(char c)
    {
        return c-'0';
    }
    void insert(char str[],int val)
    {
        int u=0;
        for(int i=0; str[i]; i++)
        {
            int c=idx(str[i]);
            if(!ch[u][c])
            {
                memset(ch[sz],0,sizeof(ch[sz]));
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        v[u]=val;
    }
    void getac()
    {
        f[0]=0;
        queue<int>q;
        for(int c=0; c<M; c++)
        {
            int u=ch[0][c];
            if(u)
            {
                f[u]=0;
                q.push(u);
                last[u]=v[u];//////////////////
            }
        }
        while(!q.empty())
        {
            int r=q.front();
            q.pop();
            for(int c=0; c<M; c++)
            {
                int u=ch[r][c];
                if(!u)
                {
                    ch[r][c]=ch[f[r]][c];
                }
                else
                {
                    q.push(u);
                    int s=f[r];
                    f[u]=ch[s][c];
                    last[u]=(v[u]||last[f[u]]);/////////////////
                }
            }
        }
    }
    int ok(int u,int k)
    {
        for(int i=3;i>=0;i--)
        {
            u=ch[u][((k>>i)&1)];
            if(last[u])
            {
                u=-1;break;
            }
        }
        return u;
    }
    int dp(int u,int sub,int up,int zero)//sub表示还剩下的位数,0表示是否前导0
    {
        if(sub==0)return 1;
        if(d[u][sub][zero]!=-1&&(!up))
        return d[u][sub][zero];
        int ans=0;
        int end=(up?idx(s[n-sub]):9);
        int i=0;
        if(zero)//处理前导0
        {
            ans+=dp(u,sub-1,up&&(0==end),1);
            ans%=mod;
            i++;
        }
        for(;i<=end;i++)
        {
            int c=ok(u,i);
            if(c!=-1)
            {
                ans+=dp(c,sub-1,up&&(i==end),0);
                ans%=mod;
            }
        }
        if(!up)
        d[u][sub][zero]=ans;
        return ans;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("ex.in","r",stdin);
    #endif
        scanf("%d",&T);
        while(T--)
        {
            init();
            scanf("%d",&n);
            for(int i=1; i<=n; ++i)
            {
                scanf("%s",str);
                insert(str,1);
            }
            getac();
            scanf("%s%s",a,b);
            n=strlen(a);
            for(int i=n-1;i>=0;i--)
            if(a[i]=='0')
                a[i]='9';
            else
            {
                a[i]--;break;//有前导0也没事
            }
            s=a;
            int ans=dp(0,n,1,1);//d[u][sub][zero]的sub是从n->0,不是从0->n(WA)
            s=b;
            n=strlen(b);
            int ans2=dp(0,n,1,1);
            ans=ans2-ans;
            if(ans<0)ans+=mod;
            ans%=mod;
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    mini2440烧写nor flash
    mini2440系统引导(五)串口UART
    mini2440系统引导(四)存储控制器
    mini2440系统引导(三)当前状态寄存器CPSR
    mini2440系统引导(二)中断寄存器
    mini2440系统引导(一)看门狗
    filebeat版本问题导致logstash无法处理接收到的日志
    kernel: possible SYN flooding on port 80. Sending cookies
    grok正则
    【转载】kafka 基础知识
  • 原文地址:https://www.cnblogs.com/sbaof/p/3377484.html
Copyright © 2011-2022 走看看