3530: [Sdoi2014]数数
Time Limit: 10 Sec Memory Limit: 512 MBDescription
我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。
给定N和S,计算不大于N的幸运数个数。
Input
输入的第一行包含整数N。
接下来一行一个整数M,表示S中元素的数量。
接下来M行,每行一个数字串,表示S中的一个元素。
Output
输出一行一个整数,表示答案模109+7的值。
Sample Input
3
2
3
14
Sample Output
HINT
下表中l表示N的长度,L表示S中所有串长度之和。
1 < =l < =1200 , 1 < =M < =100 ,1 < =L < =1500
对于这类问题,我们可以用 AC自动机套dp 来解决
因为对于位数比N少的,有前导零不好处理,所以我们分开讨论
如果位数比N少,就和N的大小没有关系,我们可以直接转移
g[i][j] 表示 当前是第 i 位 并且 走到 AC自动机上的 j 节点的方案数
转移方程就是 g[i + 1][nxt[j]] += g[i][j] (!judge[nxt[j]]);
ANS = sum(g[i][j]) (i = 1 ~ N - 1, j = 0 ~ tot);
对于 位数和N相同的类似操作, 只需要加一维 表示前缀是否和N相同 0 表示不同, 1 表示相同
如果是 0 的话后面就随便加, 1 再判断一下 , 和数位dp 思想很像
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <algorithm> 6 #define LL long long 7 8 using namespace std; 9 10 queue<int> q; 11 12 LL ans = 0; 13 14 int N, M; 15 int ln; 16 char s[2000]; 17 LL g[1300][1600]; 18 LL f[2][1300][1600]; // 1 有限制, 0 表示无限制 19 int tot = 0; 20 LL mod = 1e9 + 7; 21 22 inline LL read() 23 { 24 LL x = 0, w = 1; char ch = 0; 25 while(ch < '0' || ch > '9') { 26 if(ch == '-') { 27 w = -1; 28 } 29 ch = getchar(); 30 } 31 while(ch >= '0' && ch <= '9') { 32 x = x * 10 + ch - '0'; 33 ch = getchar(); 34 } 35 return x * w; 36 } 37 38 const int MAXN = 1e6 + 10; 39 40 int d[MAXN]; 41 42 struct trie { 43 int str[15]; 44 int fail; 45 int num; 46 int judge; 47 void init() 48 { 49 memset(str, 0, sizeof str); 50 fail = 0; 51 judge = 0; 52 } 53 } t[MAXN]; 54 55 void insert(int root, int k) 56 { 57 for(int i = 1; i <= k; i++) { 58 int nxt = s[i] - '0'; 59 if(t[root].str[nxt] == 0) { 60 t[root].str[nxt] = ++tot; 61 t[tot].init(); 62 t[tot].num = nxt; 63 } 64 root = t[root].str[nxt]; 65 } 66 t[root].judge = 1; 67 } 68 69 void getfail() 70 { 71 for(int i = 0; i <= 9; i++) { 72 if(t[0].str[i]) { 73 q.push(t[0].str[i]); 74 } 75 } 76 while(!q.empty()) { 77 int tt = q.front(); 78 q.pop(); 79 for(int j = 0; j <= 9; j++) { 80 if(t[tt].str[j]) { 81 int f = t[tt].fail; 82 while(t[f].str[j] == 0) { 83 if(f == 0) { 84 break; 85 } 86 f = t[f].fail; 87 } 88 t[t[tt].str[j]].fail = t[f].str[j]; 89 q.push(t[tt].str[j]); 90 } 91 } 92 } 93 } 94 95 int main() 96 { 97 scanf("%s", s + 1); 98 ln = strlen(s + 1); 99 for(int i = 1; i <= ln; i++) { 100 d[i] = s[i] - '0'; 101 } 102 M = read(); 103 for(int i = 1; i <= M; i++) { 104 scanf("%s", s + 1); 105 int len = strlen(s + 1); 106 insert(0, len); 107 } 108 getfail(); 109 g[0][0] = 1; 110 for(int i = 0; i < ln; i++) { 111 for(int j = 0; j <= tot; j++) { 112 for(int k = 0; k <= 9; k++) { 113 if(i == 0 && k == 0) { 114 continue; 115 } 116 int nxt = t[j].str[k]; 117 int cnt = j; 118 while(nxt == 0) { 119 if(cnt == 0) { 120 break; 121 } 122 cnt = t[cnt].fail; 123 nxt = t[cnt].str[k]; 124 } 125 if(!t[nxt].judge) { 126 g[i + 1][nxt] = (g[i + 1][nxt] + g[i][j]) % mod; 127 } 128 } 129 } 130 } 131 f[1][0][0] = 1; 132 for(int i = 0; i < ln; i++) { 133 for(int j = 0; j <= tot; j++) { 134 for(int k = 0; k <= 9; k++) { 135 if(i == 0 && k == 0) { 136 continue; 137 } 138 int nxt = t[j].str[k]; 139 int cnt = j; 140 while(nxt == 0) { 141 if(cnt == 0) { 142 break; 143 } 144 cnt = t[cnt].fail; 145 nxt = t[cnt].str[k]; 146 } 147 if(!t[nxt].judge) { 148 if(k < d[i + 1]) { 149 f[0][i + 1][nxt] = (f[0][i + 1][nxt] + f[1][i][j] + f[0][i][j]) % mod; 150 } else if(k == d[i + 1]) { 151 f[0][i + 1][nxt] = (f[0][i + 1][nxt] + f[0][i][j]) % mod; 152 f[1][i + 1][nxt] = (f[1][i + 1][nxt] + f[1][i][j]) % mod; 153 } else { 154 f[0][i + 1][nxt] = (f[0][i + 1][nxt] + f[0][i][j]) % mod; 155 } 156 } 157 } 158 } 159 } 160 for(int i = 1; i < ln; i++) { 161 for(int j = 0; j <= tot; j++) { 162 ans = (ans + g[i][j]) % mod; 163 } 164 } 165 /*for(int i = 1; i <= ln; i++) { 166 for(int j = 0; j <= tot; j++) { 167 cout<<t[j].num<<" "<<f[0][i][j]<<" "<<f[1][i][j]<<endl; 168 } 169 cout<<endl<<endl; 170 }*/ 171 for(int j = 0; j <= tot; j++) { 172 ans = (ans + f[0][ln][j] + f[1][ln][j]) % mod; 173 } 174 printf("%lld\n", ans); 175 } 176 177 178 179 /* 180 181 20 182 3 183 2 184 3 185 14 186 187 */