[bzoj3530][SDOI2014]数数
2015-12-30 19:53
477 查看
题目描述
求不大于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 [i][0]+f [i][1])%mo; printf("%lld\n",ans); }
相关文章推荐
- 自定义ImageView
- 第十三周 Prim算法的验证
- get by name
- 【游】RTS的要素
- ioS UI-导航控制器(NavigationController)
- 学生管理系统(c版)
- 自定义ProgressBar格式
- iOS开发之NSURLSession详解
- HashMap 的遍历key与value的方法 .
- Asp.Net WebAPI 通过HttpContextBase获取请求参数
- '+n+'
- JavaScript设计模式简介
- Launcher和LauncherModel之间的数据交互
- read( ) 函数 —— 终端输入设备的阻塞与非阻塞的设置
- 基于CTP的程序化交易系统开发(一)
- glib g_main_loop理解
- 边界模块-system generator
- Linux 的档案权限与目录配置
- 实验四 主存空间的分配和回收模拟
- iOS的WebView自适应内容高度