3530: [Sdoi2014]数数
2016-08-25 11:23
288 查看
3530: [Sdoi2014]数数
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 723 Solved: 385
[Submit][Status][Discuss]
Description
我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。给定N和S,计算不大于N的幸运数个数。
Input
输入的第一行包含整数N。接下来一行一个整数M,表示S中元素的数量。
接下来M行,每行一个数字串,表示S中的一个元素。
Output
输出一行一个整数,表示答案模109+7的值。Sample Input
203
2
3
14
Sample Output
14HINT
下表中l表示N的长度,L表示S中所有串长度之和。1 < =l < =1200 , 1 < =M < =100 ,1 < =L < =1500
Source
Round 1 day 1[Submit][Status][Discuss]
先构造一个AC自动机
f[i][j]:放了i位数字,现在在AC自动机的第j位,合法方案数
转移方程显然
但是这里要注意一些事情
如果我们设f[0][0] = 1为初值
搞到最后一定会把0这个东西算下去
ans - 1可以解决
但是这样又会出现一些奇怪的问题
f[k][0]这个状态一直都把含有一堆前导0的这个状态算着
如果我们的一堆子串中有一个含有前导0
那么下一次转移直接贴着这条边走过去了
就是说我们统计了一个含有前导0的数??????
所以,,,把第一位单独提出处理
以及,单独处理要新起一个头的情况
#include<iostream> #include<cstdio> #include<queue> #include<vector> #include<bitset> #include<algorithm> #include<cstring> #include<map> #include<stack> #include<set> #include<cmath> #include<ext/pb_ds/priority_queue.hpp> using namespace std; const int maxn = 2E3 + 10; const int mo = 1E9 + 7; int n,m,cnt,ch[maxn][10],fail[maxn],f[maxn][maxn]; bool Mark[maxn],Max[maxn][maxn]; char num[maxn],Num[maxn]; queue <int> Q; int main() { #ifdef DMC freopen("DMC.txt","r",stdin); #endif scanf("%s",Num + 1); n = strlen(Num + 1); cin >> m; for (int i = 1; i <= m; i++) { scanf("%s",num + 1); int len = strlen(num + 1); int now = 0; for (int j = 1; j <= len; j++) { int Nex = num[j] - '0'; if (!ch[now][Nex]) ch[now][Nex] = ++cnt; now = ch[now][Nex]; } Mark[now] = 1; } for (int i = 0; i < 10; i++) if (ch[0][i]) fail[ch[0][i]] = 0,Q.push(ch[0][i]); while (!Q.empty()) { int k = Q.front(); Q.pop(); for (int i = 0; i < 10; i++) { int u = ch[k][i]; if (!u) { ch[k][i] = ch[fail[k]][i]; continue; } int v = fail[k]; fail[u] = ch[v][i]; Q.push(u); } } for (int Nex = 1; Nex < 10; Nex++) { if (Mark[ch[0][Nex]]) continue; ++f[1][ch[0][Nex]]; if (Nex > Num[1] - '0') --f[1][ch[0][Nex]]; if (Nex == Num[1] - '0') Max[1][ch[0][Nex]] = 1; } for (int i = 1; i < n; i++) { for (int j = 0; j <= cnt; j++) { if (!f[i][j]) continue; for (int Nex = 0; Nex < 10; Nex++) { if (Mark[ch[j][Nex]]) continue; f[i+1][ch[j][Nex]] += f[i][j]; f[i+1][ch[j][Nex]] %= mo; if (Max[i][j] && Nex > Num[i+1] - '0') { --f[i+1][ch[j][Nex]]; f[i+1][ch[j][Nex]] = (f[i+1][ch[j][Nex]] + mo) % mo; } if (Max[i][j] && Nex == Num[i+1] - '0') Max[i+1][ch[j][Nex]] = 1; } } for (int Nex = 1; Nex < 10; Nex++) { if (Mark[ch[0][Nex]]) continue; ++f[i+1][ch[0][Nex]]; f[i+1][ch[0][Nex]] %= mo; } } int Ans = 0; for (int i = 0; i <= cnt; i++) Ans += f [i],Ans %= mo; cout << Ans; return 0; }
相关文章推荐
- bzoj 3530: [Sdoi2014]数数 AC自动机&动态规划
- 【BZOJ】【3530】【SDOI2014】数数
- bzoj3530 [Sdoi2014]数数(AC自动机+数位DP)
- bzoj 3530 : [Sdoi2014]数数
- bzoj 3530: [Sdoi2014]数数 (AC自动机+数位DP)
- [BZOJ3530][Sdoi2014]数数(AC自动机上数位DP)
- BZOJ.3530.[SDOI2014]数数(AC自动机 数位DP)
- 【BZOJ3530】数数(SDOI2014)-AC自动机+数位DP
- 【BZOJ3530】[Sdoi2014]数数 AC自动机+数位DP
- [BZOJ3530] [Sdoi2014]数数 && AC自动机+dp
- bzoj 3530: [Sdoi2014]数数
- Bzoj3530 [Sdoi2014]数数
- [bzoj3530][SDOI2014]数数
- bzoj 3530: [Sdoi2014]数数 数位dp
- 【bzoj3530】[Sdoi2014]数数 AC自动机+数位dp
- 【BZOJ 3530】【SDOI 2014】数数
- [BZOJ3530][Sdoi2014]数数(AC自动机+数位DP)
- 【bzoj3530】【sdoi2014】【数数】【AC自动机+数位dp】
- [BZOJ3530][SDOI2014]数数 AC自动机+数位DP
- [BZOJ3530][Sdoi2014]数数(AC自动机+数位dp)