题意:
给出n个非法串,给出一个范围,求这个范围的数转成定义串不包含非法的个数。所谓定义串,举个例子比如27,7的二进制是0111,2的二进制是0010 那么27变成定义串就是 0010 0111。
题解:
明显是数位dp,ac自动机上的数位dp。一开始把数字全弄成二进制来做,也是脑残了。直接数位dp,dfs就好了,状态很简单dp[pos][i]位数pos,在自动机上i点。注意高进度的减法,范围的下限要减1。还有就是前导零的问题,dfs时多设一个变量判断前导零,这些都是很基本的数位dp,不难。
以前学数位dp就养成了dfs写的习惯,说实话dfs的确好写,感觉无脑操作。递推很容漏掉情况所以不怎么好写。尤其是这类有范围的,特别容易漏。不过在一些情况下递推写法很精简。
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define B(x) (1<<(x))
typedef long long ll;
const int oo=0x3f3f3f3f;
const ll OO=1LL<<61;
const ll MOD=1000000009;
const int maxn=208;
const int digs=208;
const int SIZE=2005;
const int alph=2;
char A[maxn],B[maxn],str[30];
ll dp[digs][SIZE];
int bit[digs],len;
struct AC
{
int next[SIZE][alph],fail[SIZE],flag[SIZE];
int root,cnt;
void Init()
{
cnt=0;
root=newNode();
}
int newNode()
{
for(int i=0;i<alph;i++)
next[cnt][i]=-1;
flag[cnt++]=0;
return cnt-1;
}
void Insert(char buff[])
{
int now=root;
int len=strlen(buff);
for(int i=0,k;i<len;i++)
{
k=buff[i]-'0';
if(next[now][k]==-1)
next[now][k]=newNode();
now=next[now][k];
}
flag[now]=1;
}
void build()
{
queue<int>Q;
fail[root]=root;
int now=root;
for(int i=0;i<alph;i++)
{
if(next[now][i]==-1)
next[now][i]=root;
else
{
fail[next[now][i]]=root;
Q.push(next[now][i]);
}
}
while(!Q.empty())
{
now=Q.front();
Q.pop();
if(flag[fail[now]]==1) flag[now]=1;
for(int i=0;i<alph;i++)
{
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else
{
fail[next[now][i]]=next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
}
int GetNext(int now,int num)
{
int temp[4];
for(int i=0;i<4;i++)
{
temp[i]=num%2;
num/=2;
}
for(int i=3;i>=0;i--)
{
now=next[now][temp[i]];
if(flag[now]) return -1;
}
return now;
}
ll dfs(int pos,int i,int f,int pre0)
{
if(pos<1) return 1;
if(pre0&&!f&&dp[pos][i]!=-1) return dp[pos][i];
int last= f ? bit[pos] : 9;
ll res=0;
for(int num=0;num<=last;num++)
{
if(pre0==0&&num==0)
{
res=(res+dfs(pos-1,0,f&&num==last,pre0)+MOD)%MOD;
continue;
}
int k=GetNext(i,num);///判断是否有包含,没有返回next,有返回-1
if(k!=-1)
res=(res+dfs(pos-1,k,f&&num==last,pre0||num)+MOD)%MOD;
}
if(!f&&pre0==1) dp[pos][i]=res;
return res;
}
ll Cnt(char s[])
{
len=strlen(s);
for(int i=0;i<len;i++)
bit[i+1]=s[len-i-1]-'0';
while(bit[len]==0&&len>0)--len;
if(len<1)bit[++len]=0;
return dfs(len,0,1,0);
}
ll DP(char s1[],char s2[])
{
memset(dp,-1,sizeof dp);
///将s1减去1
int l1=strlen(s1)-1;
for(int i=l1;i>=0;i--)
{
if(s1[i]>'0')
{
s1[i]--;
break;
}
else
s1[i]='9';
}
return (Cnt(s2)-Cnt(s1)+MOD)%MOD;
}
};
AC ac;
int main()
{
int n,T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
ac.Init();
for(int i=1;i<=n;i++)
{
scanf("%s",str);
ac.Insert(str);
}
ac.build();
scanf("%s %s",A,B);
cout<<ac.DP(A,B)<<endl;
}
return 0;
}
/**
3
1
00
1 10
1
00
1 100
1
1111
1 100
*/