ZOJ 3494 (AC自动机+数位DP)
题意:给n个01字符串,求区间[x , y]中有多少个数写成BCD码后不包含以上01串。
分析:先用01字符串建立AC自动机(注意标记危险结点),然后DP。dp[i][s]表示扫描前i位后有多少个数会到达自动机的结点s.
注意:
1.前导0的问题:不能转化成二进制在数位dp(否则处理不了前导0),安十进制进行数位dp!
2.d[u][sub][zero]的sub是从n->0,不是从0->n(sub表示还剩几位) Orz。。。
//#pragma comment(linker, "/STACK:102400000") #include<cstdlib> #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<map> #include<list> #include<queue> #include<stack> #include<vector> #define tree int o,int l,int r #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define lo o<<1 #define ro o<<1|1 #define pb push_back #define mp make_pair #define ULL unsigned long long #define LL long long #define inf 0x7fffffff #define eps 1e-7 #define N 2009 #define M 2 #define mod 1000000009 using namespace std; int m,n,T,t,x,y,u; int ch[N][M],v[N],sz; int f[N],last[N],len; char str[29],a[209],b[209],*s; int d[N][809][2]; char tr[10][5]={"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001"}; void init() { sz=1; memset(ch[0],0,sizeof(ch[0])); memset(v,0,sizeof(v)); memset(last,0,sizeof(last)); memset(d,-1,sizeof(d)); } int idx(char c) { return c-'0'; } void insert(char str[],int val) { int u=0; for(int i=0; str[i]; i++) { int c=idx(str[i]); if(!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); ch[u][c]=sz++; } u=ch[u][c]; } v[u]=val; } void getac() { f[0]=0; queue<int>q; for(int c=0; c<M; c++) { int u=ch[0][c]; if(u) { f[u]=0; q.push(u); last[u]=v[u];////////////////// } } while(!q.empty()) { int r=q.front(); q.pop(); for(int c=0; c<M; c++) { int u=ch[r][c]; if(!u) { ch[r][c]=ch[f[r]][c]; } else { q.push(u); int s=f[r]; f[u]=ch[s][c]; last[u]=(v[u]||last[f[u]]);///////////////// } } } } int ok(int u,int k) { for(int i=3;i>=0;i--) { u=ch[u][((k>>i)&1)]; if(last[u]) { u=-1;break; } } return u; } int dp(int u,int sub,int up,int zero)//sub表示还剩下的位数,0表示是否前导0 { if(sub==0)return 1; if(d[u][sub][zero]!=-1&&(!up)) return d[u][sub][zero]; int ans=0; int end=(up?idx(s[n-sub]):9); int i=0; if(zero)//处理前导0 { ans+=dp(u,sub-1,up&&(0==end),1); ans%=mod; i++; } for(;i<=end;i++) { int c=ok(u,i); if(c!=-1) { ans+=dp(c,sub-1,up&&(i==end),0); ans%=mod; } } if(!up) d[u][sub][zero]=ans; return ans; } int main() { #ifndef ONLINE_JUDGE freopen("ex.in","r",stdin); #endif scanf("%d",&T); while(T--) { init(); scanf("%d",&n); for(int i=1; i<=n; ++i) { scanf("%s",str); insert(str,1); } getac(); scanf("%s%s",a,b); n=strlen(a); for(int i=n-1;i>=0;i--) if(a[i]=='0') a[i]='9'; else { a[i]--;break;//有前导0也没事 } s=a; int ans=dp(0,n,1,1);//d[u][sub][zero]的sub是从n->0,不是从0->n(WA) s=b; n=strlen(b); int ans2=dp(0,n,1,1); ans=ans2-ans; if(ans<0)ans+=mod; ans%=mod; printf("%d\n",ans); } return 0; }