题意:给定的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; }