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\n",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;
}

 

posted @ 2018-11-25 18:28  guapisolo  阅读(169)  评论(0编辑  收藏  举报