[bzoj3530][SDOI2014]数数

来源:互联网 发布:影视大全源码安装 编辑:程序博客网 时间:2024/05/21 03:19

题目描述

求不大于N的所有正整数中有多少个满足以下条件的数:给定字符串集合S,把该数当作字符串(没有前导0),集合S中没有任意一个字符串是该字符串的子集。
N的长度不超过1200,集合中所有字符串长度和不超过1500。

AC自动机上的DP

将集合内所有字符串建出一颗AC自动机。
那么,我们需要预处理一个这样的next[i,j]表示在结点i上接下要走j的话会调整到的结点是什么。(即预处理所有可能出现的调整结果)。
接下来就是数位DP了,设f[i,j,0]表示在第i位在AC自动机的结点j,当前比前i位比N小,那么f[i,j,1]就是与N相同,转移显然。
跳过所有状态满足当前结点可以匹配到一个单词(即S内的一个字符串),这样的结点j满足bz[j]=1(它是单词结点)或last[j]>0(它可以通过fail指针调整而匹配成功)。

参考程序

#include<cstdio>#include<algorithm>#include<cstring>#include<deque>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;const ll mo=1000000007;struct dong{    ll x,y;};deque<dong> dl;ll next[1500+10][15],g[1500+10][15],fail[1500+10],last[1500+10];bool bz[1500+10];ll f[1200+10][1500+10][2];ll i,j,k,l,t,n,m,top,tot,ans;char s[1500+10],h[1500+10],ch;dong zlt;void insert(ll x,ll y){    if (y>top){        bz[x]=1;        return;    }    if (g[x][h[y]-'0']==-1){        g[x][h[y]-'0']=++tot;        ll i;        fo(i,0,9) g[tot][i]=-1;    }    insert(g[x][h[y]-'0'],y+1);}void bfs(){    fo(i,0,9)        if (g[0][i]!=-1){            zlt.x=g[0][i];zlt.y=0;            dl.push_back(zlt);        }    while (!dl.empty()){        zlt=dl.front();        dl.pop_front();        k=zlt.x;l=zlt.y;        fail[k]=l;        if (bz[l]) last[k]=l;else last[k]=last[l];        fo(i,0,9){            if (g[k][i]==-1) continue;            j=l;            while (j&&g[j][i]==-1) j=fail[j];            if (g[j][i]!=-1) j=g[j][i];            zlt.x=g[k][i];zlt.y=j;            dl.push_back(zlt);        }    }}void getnext(){    fo(i,0,tot){        fo(k,0,9){            j=i;            while (j&&g[j][k]==-1) j=fail[j];            if (g[j][k]!=-1) j=g[j][k];            next[i][k]=j;        }    }}int main(){    //freopen("count.in","r",stdin);freopen("count.out","w",stdout);    do{        ch=getchar();        if (ch=='\n') break;        s[++n]=ch;    }while (1);    scanf("%lld",&m);    ch=getchar();    fo(i,0,9) g[0][i]=-1;    fo(i,1,m){        top=0;        do{            ch=getchar();            if (ch=='\n') break;            h[++top]=ch;        }while (1);        insert(0,1);    }    bfs();    getnext();    fo(i,1,s[1]-'0'-1) f[1][next[0][i]][0]=(f[1][next[0][i]][0]+1)%mo;    f[1][next[0][s[1]-'0']][1]=(f[1][next[0][s[1]-'0']][1]+1)%mo;    fo(i,1,n-1){        fo(j,1,9) f[i+1][next[0][j]][0]=(f[i+1][next[0][j]][0]+1)%mo;        fo(j,0,tot){            if (bz[j]||last[j]) continue;            if (f[i][j][0])                fo(k,0,9) f[i+1][next[j][k]][0]=(f[i+1][next[j][k]][0]+f[i][j][0])%mo;            if (f[i][j][1]){                fo(k,0,s[i+1]-'0'-1) f[i+1][next[j][k]][0]=(f[i+1][next[j][k]][0]+f[i][j][1])%mo;                f[i+1][next[j][s[i+1]-'0']][1]=(f[i+1][next[j][s[i+1]-'0']][1]+f[i][j][1])%mo;            }        }    }    ans=0;    fo(i,0,tot)        if (!bz[i]&&!last[i]) ans=(ans+f[n][i][0]+f[n][i][1])%mo;    printf("%lld\n",ans);}
0 0
原创粉丝点击