题意:
Binary-coded decimal (BCD) is an encoding for decimal numbers in which each digit is represented by its own binary sequence. To encode a decimal number using the common BCD encoding, each decimal digit is stored in a 4-bit nibble:
Decimal: 0 1 2 3 4 5 6 7 8 9
BCD: 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001
Thus, the BCD encoding for the number 127 would be:
0001 0010 0111
We are going to transfer all the integers from A to B, both inclusive, with BCD codes. But we find that some continuous bits, named forbidden code, may lead to errors. If the encoding of some integer contains these forbidden codes, the integer can not be transferred correctly. Now we need your help to calculate how many integers can be transferred correctly.
Input
There are multiple test cases. The first line of input is an integer T ≈ 100 indicating the number of test cases.
The first line of each test case contains one integer N, the number of forbidden codes ( 0 ≤ N ≤ 100). Then N lines follow, each of which contains a 0-1 string whose length is no more than 20. The next line contains two positive integers A and B. Neither A or B contains leading zeros and 0 < A ≤ B < 10^200.
Output
For each test case, output the number of integers between A and B whose codes do not contain any of the N forbidden codes in their BCD codes. For the result may be very large, you just need to output it mod 1000000009.
题解:
AC自动机+数位DP
多串问题直接上AC自动机,看A,B的范围也应该能知道数位DP
先用所有禁止串建立AC自动机,处理出所有可能被禁止的串,然后跑数位DP,跳过这些节点就好了。怎么跳过呢?因为每一个禁止串都是4位2进制码,我们可以预处理一个bcd[i][j]表示当前在AC自动机上的i节点,和它相连且他们之间组成的十进制数是j的点的节点标号。然后将不存在边的直接置为-1,跳过即可。
这道题坑的是mod 1e9+9 - -!气哭
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 2050;
const int INF = 0x3f3f3f3f;
const int MOD = 1000000009;
char ss[MAXN],ll[MAXN],rr[MAXN];
int nxt[MAXN][2],fail[MAXN],vis[MAXN],dig[MAXN],bcd[MAXN][10],tot;
LL dp[205][MAXN];
inline void Init(){
for(int i=0;i<=tot;i++){
fail[i]=vis[i]=0;
for(int j=0;j<2;j++) nxt[i][j]=0;
}
tot=1;
}
inline void Insert(char *s){
int rt=0,len=strlen(s);
for(int i=0;i<len;i++){
if(!nxt[rt][s[i]-'0']) nxt[rt][s[i]-'0']=++tot;
rt = nxt[rt][s[i]-'0'];
}
vis[rt]=1;
}
inline void Build(){
queue<int> que;
for(int i=0;i<2;i++) if(nxt[0][i]) que.push(nxt[0][i]);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=0;i<2;i++){
if(nxt[u][i]){
fail[nxt[u][i]] = nxt[fail[u]][i];
que.push(nxt[u][i]);
vis[nxt[u][i]] |= vis[nxt[fail[u]][i]];
}else{
nxt[u][i] = nxt[fail[u]][i];
}
}
}
}
inline int check(int rt,int num){
if(vis[rt]) return -1;
for(int i=3;i>=0;i--){
if(vis[nxt[rt][(num>>i)&1]]) return -1;
rt = nxt[rt][(num>>i)&1];
}
return rt;
}
inline void pre(){
for(int i=0;i<=tot;i++)
for(int j=0;j<10;j++)
bcd[i][j]=check(i,j);
}
LL dfs(int pos,int sta,bool limit,bool lead){
if(sta==-1) return 0;
if(pos==-1) return 1;
if(!limit && !lead && dp[pos][sta]!=-1) return dp[pos][sta];
int up=limit ? dig[pos]:9;
LL res=0;
for(int i=0;i<=up;i++){
if(i==0 && lead) res = (res+dfs(pos-1,sta,limit && i==up,lead && i==0))%MOD;
else res = (res+dfs(pos-1,bcd[sta][i],limit && i==up,lead && i==0))%MOD;
}
if(!limit && !lead) dp[pos][sta]=res;
return res;
}
inline LL solve(char *s){
int pos=0,len=strlen(s);
for(int i=len-1;i>=0;i--) dig[pos++] = s[i]-'0';
return dfs(pos-1,0,1,1);
}
int main(){
int T; scanf("%d",&T);
while(T--){
Init();
int n; scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%s",ss),Insert(ss);
Build();
pre();
scanf("%s%s",ll,rr);
int len=strlen(ll);
for(int i=len-1;i>=0;i--){
if(ll[i]=='0') ll[i]='9';
else { ll[i]--; break; }
}
memset(dp,-1,sizeof(dp));
LL res = solve(rr)-solve(ll);
printf("%lld\n",(res+MOD)%MOD);
}
return 0;
}