bzoj 3530: [Sdoi2014]数数
2017-10-08 21:33
603 查看
Description
我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。给定N和S,计算不大于N的幸运数个数。解题报告
简单题,但有点坑,首先如果没有限制就是一个数位DP板子,对于包含的限制,一般是加一维在AC自动机上的节点号,这样就可以保证不存在包含关系了.设状态 \(f[i][j][k][l]\) 表示前i位数字,目前在AC自动机上的j号节点,选的数字为k,是否严格小于\(0/1\),其实我是个傻逼,写完以后猛地发现 \(k\) 这一维是多余的,而且还需要滚动,但还是讲一下我的做法吧,如果严格小于就可以任意选,前缀都相等,就只能选小于 \(N\) 的这一位的数字,如果走出了包含关系,就不转移.
最坑的地方来了:
10 1 03
这一组数据,如果不判前导0,那么输出\(9\), \(3\) 就被完美的忽略了,所以把 \(k\) 这一位加一个状态,表示前导0然后特殊转移即可
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <queue> #include <cmath> #define RG register #define il inline #define iter iterator #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; const int N=20005,mod=1e9+7; int f[2] [11][2],fail ,s ,n,m;char S ; struct node{ int nxt[11],mark; }a ; void upd(int &x,int y){x+=y;if(x>=mod)x-=mod;} int root=0,cnt=0; void add(){ scanf("%s",S); int len=strlen(S),p=0; for(int i=0;i<len;i++){ if(a[p].nxt[S[i]-'0'])p=a[p].nxt[S[i]-'0']; else a[p].nxt[S[i]-'0']=++cnt,p=cnt; } a[p].mark=1; } queue<int>q; void getfail(){ q.push(root); int x,u,v; while(!q.empty()){ x=q.front();q.pop(); for(int i=0;i<10;i++){ if(!a[x].nxt[i]){ a[x].nxt[i]=a[fail[x]].nxt[i]; continue; } u=fail[x]; while(u && !a[u].nxt[i])u=fail[u]; if(a[u].nxt[i] && a[u].nxt[i]!=a[x].nxt[i]) fail[a[x].nxt[i]]=a[u].nxt[i]; v=a[x].nxt[i];a[v].mark|=a[fail[v]].mark;q.push(v); } } } void work() { scanf("%s%d",S+1,&m);n=strlen(S+1); for(int i=1;i<=n;i++)s[i]=S[i]-'0'; for(int i=1;i<=m;i++)add(); getfail(); int x,to,b;bool t=0,tt=1; for(int i=1;i<=s[1];i++){ x=a[root].nxt[i]; if(a[x].mark)continue; f[t][x][i][i<s[1]]=1; } f[t][0][10][1]=1; for(int i=1;i<n;i++){ for(int j=0;j<=cnt;j++){ for(int k=0;k<=9;k++){ x=f[t][j][k][0];f[t][j][k][0]=0; if(x){ for(int l=0;l<=s[i+1];l++){ to=a[j].nxt[l];if(a[to].mark)continue; b=(l<s[i+1]); upd(f[tt][to][l][b],x); } } x=f[t][j][k][1];f[t][j][k][1]=0; if(x){ for(int l=0;l<10;l++){ to=a[j].nxt[l];if(a[to].mark)continue; upd(f[tt][to][l][1],x); } } } x=f[t][j][10][1];f[t][j][10][1]=0; for(int l=1;l<=10;l++){ to=a[j].nxt[l];if(a[to].mark)continue; upd(f[tt][to][l][1],x); } } t^=1;tt^=1; } int ans=0; for(int i=0;i<=cnt;i++) for(int k=0;k<=10;k++) for(int l=0;l<=1;l++) upd(ans,f[t][i][k][l]); ans=(ans-1+mod)%mod; printf("%d\n",ans); } int main(){work();return 0;}
相关文章推荐
- [BZOJ3530]-[Sdoi2014]数数-AC自动机+数位DP
- 【BZOJ3530】[Sdoi2014]数数 AC自动机+数位DP
- BZOJ3530:[SDOI2014]数数——题解
- [bzoj3530][Sdoi2014]数数_AC自动机_数位dp
- BZOJ.3530.[SDOI2014]数数(AC自动机 数位DP)
- [BZOJ3530][Sdoi2014]数数(AC自动机+数位DP)
- [BZOJ 3530] [Sdoi2014] 数数 【AC自动机+DP】
- 【BZOJ3530】数数(SDOI2014)-AC自动机+数位DP
- bzoj 3530: [Sdoi2014]数数
- BZOJ 3530 【Sdoi2014】 数数
- [BZOJ3530][SDOI2014]数数 AC自动机+数位DP
- bzoj 3530: [Sdoi2014]数数 (AC自动机+数位DP)
- [BZOJ3530][SDOI2014]数数(AC自动机+数位dp)
- BZOJ 3530: [Sdoi2014]数数 [AC自动机 数位DP]
- [bzoj3530][SDOI2014]数数
- BZOJ3530 [SDOI2014]数数
- [BZOJ3530][Sdoi2014]数数(AC自动机+数位dp)
- 【BZOJ】【3530】【SDOI2014】数数
- [BZOJ]3530 [SDOI2014] 数数 AC自动机 + DP
- [BZOJ3530] [Sdoi2014]数数 && AC自动机+dp