题意:给定的BCD吗,当翻译十进制数时,最终形成的01串中可能有禁止出现的子串,叫我们求[a,b]中有多少个完全正确的数。
做法:对于禁止的串,直接AC自动机处理。以为a,b都是大数,所以a要先用大数减法减1。
最近不知道是不是记忆化搜索用上瘾了。。。。记录的状态是当前字符所在tire树中的位置,还有是不是数组首位,以及是不是在测层边界上的数。这个题中最首位数的处理要小心。还好只是一个RE之后就A了,本来以为可以调很久。
#include<cstdio>
#include<cstring>
#include<deque>
#define mod 1000000009
#define LL long long
const int LMT=203;
const int wiz=2;
const int WEI=4;
using namespace std;
int code[10],gra[3002][2],fail[3002],siz;
bool word[3002];
char num[LMT];
LL dp[3002][LMT];
int len;
void insert(char sor[])
{
int index,current =0;
for(int i=0;sor[i];i++)
{
index=sor[i]-'0';
if(!gra[current][index])gra[current][index]=siz++;
current=gra[current][index];
}
word[current]|=1;
}
void build_ac(void)
{
int current,v;
deque<int>q;
q.clear();
for(int i=0;i<wiz;i++)
if(gra[0][i])q.push_back(gra[0][i]);
while(!q.empty())
{
current=q.front();
q.pop_front();
for(int i=0;i<wiz;i++)
if(gra[current][i])
{
v=gra[current][i];
fail[v]=gra[fail[current]][i];
word[v]|=word[fail[v]];
q.push_back(v);
}
else gra[current][i]=gra[fail[current]][i];
}
}
void init(void)
{
siz=1;
memset(word,0,sizeof(word));
memset(fail,0,sizeof(fail));
memset(gra,0,sizeof(gra));
memset(dp,-1,sizeof(dp));
memset(num,0,sizeof(num));
}
LL dfs(int node,int pos,bool tag,bool first)
{
if(pos==-1)
{
if(first)
{
int tem=node;
for(int j=WEI-1;j>=0&&!word[tem];j--)
tem=gra[tem][0];
return !word[tem];
}
else return !word[node];
}
if(dp[node][pos]!=-1&&!tag&&!first)return dp[node][pos];
int i,j,x,end,tem;
LL res=0;
if(tag)end=num[pos];
else end=9;
for(i=first;i<=end;i++)
{
x=code[i];tem=node;
for(j=WEI-1;j>=0&&!word[tem];j--)
tem=gra[tem][(x>>j)&1];
if(word[tem])continue;
res+=dfs(tem,pos-1,tag&&i==end,0);
res%=mod;
}
if(first)res+=dfs(node,pos-1,tag&&i==end,1);
if(!first&&!tag&&dp[node][pos]==-1)dp[node][pos]=res;
return res;
}
void cut()
{
int i,j,c=1;
char a[LMT];
memset(a,0,sizeof(a));
for(i=len-1,j=0;i>=0;i--,j++)
{
a[j]=num[i];
}
memset(num,0,sizeof(num));
for(i=0;i<LMT&&c;i++)
{
a[i]=a[i]-c;
if(a[i]<0)
{
a[i]=9;
c=1;
}
else c=0;
}
for(i=LMT-1;i>=0&&a[i]==0;i--);
len=i+1;
if(i<0)len=1;
for(i=len-1,j=0;i>=0;i--,j++)num[j]=a[i];
}
int main(void)
{
int T,i,n;
char sec[25];
LL a,b;
for(i=0;i<10;i++)code[i]=i;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d",&n);
while(n--)
{
scanf("%s",sec);
insert(sec);
}
build_ac();
scanf("%s",num);
len=strlen(num);
for(i=0;num[i];i++)num[i]-='0';
cut();
for(i=0;i<len>>1;i++)swap(num[i],num[len-i-1]);
a=dfs(0,len-1,1,1);
memset(num,0,sizeof(num));
scanf("%s",num);
len=strlen(num);
for(i=0;i<len;i++)num[i]-='0';
for(i=0;i<len>>1;i++)swap(num[i],num[len-i-1]);
b=dfs(0,len-1,1,1);
printf("%lld\n",(b-a+mod)%mod);
}
return 0;
}