• BZOJ 3530 [SDOI2014]数数 (Trie图/AC自动机+数位DP)


    题目大意:略

    裸的AC自动机+数位DP吧...

    定义f[i][x][0/1]表示已经匹配到了第i位,当前位置是x,0表示没到上限,1到上限,此时数是数量

    然而会出现虚拟前导零,即前几位没有数字的情况,实际上是在0号节点原地打转,所以多加一维状态,再额外讨论第1位就行了

    #include <cmath>
    #include <queue>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define NN 1210
    #define MM 1510
    #define ll long long
    #define dd double  
    #define uint unsigned int
    #define mod 1000000007
    #define idx(X) (X-'0')
    #define eps (1e-9)
    using namespace std;
     
    int n,m,cte;
    int head[NN];
    struct Edge{int to,nxt;}edge[NN*2];
    void ae(int u,int v){
        cte++;edge[cte].nxt=head[u];
        head[u]=cte,edge[cte].to=v;
    }
    uint f[NN][MM][3];
    int ma[NN];
     
    namespace AC{
    int ch[NN][26],fail[NN],tot,ed[NN];
    void Build_Trie(char *str,int len)
    {
        int x=0;
        for(int i=1;i<=len;i++){
            if(!ch[x][idx(str[i])])
                ch[x][idx(str[i])]=++tot;
            x=ch[x][idx(str[i])];
        }ed[x]=1;
    }
    void Build_Fail()
    {
        queue<int>q;
        for(int i=0;i<=9;i++)
            if(ch[0][i]) q.push(ch[0][i]);
        while(!q.empty())
        {
            int x=q.front();q.pop();
            ae(fail[x],x);
            for(int i=0;i<=9;i++)
            {
                if(ch[x][i]){
                    fail[ch[x][i]]=ch[fail[x]][i];
                    q.push(ch[x][i]);
                }else{
                    ch[x][i]=ch[fail[x]][i];
                }
            }
        }
        q.push(0);
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int j=head[x];j;j=edge[j].nxt){
                int v=edge[j].to;
                ed[v]|=ed[x];
                q.push(v);
            }
        }
    }
    void solve()
    {
        f[1][0][2]++;
        for(int j=1;j<ma[1];j++){
            if(!ed[ch[0][j]])
            f[1][ch[0][j]][0]++;}
        if(!ed[ch[0][ma[1]]])
            f[1][ch[0][ma[1]]][1]++;
        for(int i=1;i<n;i++)
        {
            f[i+1][0][2]=1;
            int x=0;
            //nolimited
            for(int j=0;j<=9;j++){
                if(!ed[ch[x][j]])
                (f[i+1][ch[x][j]][0]+=f[i][x][0]+((j!=0)?f[i][x][2]:0))%=mod;
            }
            //limited
            for(int j=0;j<ma[i+1];j++)
                if(!ed[ch[x][j]])
                (f[i+1][ch[x][j]][0]+=f[i][x][1])%=mod;
            if(!ed[ch[x][ma[i+1]]]) 
                (f[i+1][ch[x][ma[i+1]]][1]+=f[i][x][1])%=mod;
            for(x=1;x<=tot;x++)
            {
                //nolimited
                for(int j=0;j<=9;j++){
                    if(!ed[ch[x][j]])
                    (f[i+1][ch[x][j]][0]+=f[i][x][0])%=mod;
                }
                //limited
                for(int j=0;j<ma[i+1];j++)
                    if(!ed[ch[x][j]])
                    (f[i+1][ch[x][j]][0]+=f[i][x][1])%=mod;
                if(!ed[ch[x][ma[i+1]]]) 
                    (f[i+1][ch[x][ma[i+1]]][1]+=f[i][x][1])%=mod;
                //(f[i+1][ch[x][0]][2]+=f[i][x][2])%=mod;
            }    
        }
        uint ans=0;
        for(int x=0;x<=tot;x++)
            (ans+=f[n][x][0]+f[n][x][1])%=mod;
        printf("%u
    ",ans);
    }
    };
    char str[NN];
     
    int main()
    {
        //freopen("t1.in","r",stdin);
        scanf("%s",str+1);
        n=strlen(str+1);
        for(int i=1;i<=n;i++)
            ma[i]=idx(str[i]);
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%s",str+1);
            int len=strlen(str+1);
            AC::Build_Trie(str,len);
        }AC::Build_Fail();
        AC::solve();
        return 0;
    }
  • 相关阅读:
    【UOJ#77】A+B Problem
    【AGC048B】Bracket Score
    ubuntu 下python opengl编程(2)
    网站建设的营销途径
    python脚本初探---新手写的QQ邮箱发送脚本
    Cstyle的C语言笔记 ---UEFI当中的面向对象模式
    date得到当前日期
    简单几步让SecureCRT更舒服【图文并茂】
    苹果的airplayer推荐
    【Cocos2d-X开发学习笔记】第22期:事件处理机制之触屏事件
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10016571.html
Copyright © 2020-2023  润新知