题意:
每一位数对应一种BCD编码:
Decimal: 0 1 2 3 4 5 6 7 8 9
BCD: 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001r
如127对应的BCD编码是0001 0010 0111
先给出n个不合法的BCD编码串,求[A,B]中转化成BCD编码后不包含这n个编码串中的任意一个的数的个数
0<A≤B<10200 0 < A ≤ B < 10 200
n<=100,字符串长<=20
Solution:
一眼AC自动机+数位dp
f[i][j][0/1][0/1] f [ i ] [ j ] [ 0 / 1 ] [ 0 / 1 ] 表示前i位,在AC自动机的j节点,是否到达上界,是否是前导零
记忆化搜索即可
此题用来练习代码能力不错
注意一定要dfs!!!
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int root=1;
const int mod=1e9+9;
int siz,tr[2010][2],tag[2010],ans;
int T,n;
char s[110],num[210];
int tot;
int fail[2010];
int q[2010],h,t;
int f[210][2010][2][2];
int le[10];
int a[10][4];
bool p=0;
bool vis[210][2010][2][2];
int size,head[2010];
struct eg{
int to,next;
}e[2010];
void add(int x,int y)
{
size++;
e[size].to=y;
e[size].next=head[x];
head[x]=size;
}
void insert(char s[])
{
int nw=root,len=strlen(s);
for (int i=0;i<len;i++)
{
if (!tr[nw][s[i]-'0'])
{
tr[nw][s[i]-'0']=++siz;
fail[siz]=tr[siz][0]=tr[siz][1]=tag[siz]=0;
}
nw=tr[nw][s[i]-'0'];
}
tag[nw]=1;
}
void get_fail()
{
h=t=0;
q[++t]=root;
while (h<t)
{
int x=q[++h];
for (int i=0;i<=1;i++)
if (tr[x][i])
{
if (x==root) fail[tr[x][i]]=root,add(root,tr[x][i]);
else fail[tr[x][i]]=tr[fail[x]][i],add(tr[fail[x]][i],tr[x][i]);
q[++t]=tr[x][i];
}
else
{
if (x==root) tr[x][i]=root;
else tr[x][i]=tr[fail[x]][i];
}
}
}
int dp(int len,int pos,bool edg,bool zero)
{
if (len>tot) return 1;
if (vis[len][pos][edg][zero]) return f[len][pos][edg][zero];
int temp=pos;
vis[len][pos][edg][zero]=1;
for (int i=0;i<=(edg?num[len]-'0':9);i++)
{
temp=pos;
if (i==0&&zero) f[len][pos][edg][zero]=(f[len][pos][edg][zero]+dp(len+1,temp,edg&&(i==num[len]-'0'),zero))%mod;
else
{
p=0;
for (int j=0;j<le[i];j++)
{
temp=tr[temp][a[i][j]];
if (tag[temp]) {p=1;break;}
}
if (!p) f[len][pos][edg][zero]=(f[len][pos][edg][zero]+dp(len+1,temp,edg&&(i==num[len]-'0'),0))%mod;
}
}
return f[len][pos][edg][zero];
}
void dfs(int x,int fa,int sum)
{
tag[x]=sum;
for (int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
dfs(y,x,sum|tag[y]);
}
}
bool pan()
{
int nw=root;
for (int i=1;i<=tot;i++)
for (int j=0;j<le[num[i]-'0'];j++)
{
nw=tr[nw][a[num[i]-'0'][j]];
if (tag[nw]) return 0;
}
return 1;
}
int main()
{
// freopen("3494.in","r",stdin);
// freopen("3494.out","w",stdout);
a[0][0]=0;a[0][1]=0;a[0][2]=0;a[0][3]=0;le[0]=4;
a[1][0]=0;a[1][1]=0;a[1][2]=0;a[1][3]=1;le[1]=4;
a[2][0]=0;a[2][1]=0;a[2][2]=1;a[2][3]=0;le[2]=4;
a[3][0]=0;a[3][1]=0;a[3][2]=1;a[3][3]=1;le[3]=4;
a[4][0]=0;a[4][1]=1;a[4][2]=0;a[4][3]=0;le[4]=4;
a[5][0]=0;a[5][1]=1;a[5][2]=0;a[5][3]=1;le[5]=4;
a[6][0]=0;a[6][1]=1;a[6][2]=1;a[6][3]=0;le[6]=4;
a[7][0]=0;a[7][1]=1;a[7][2]=1;a[7][3]=1;le[7]=4;
a[8][0]=1;a[8][1]=0;a[8][2]=0;a[8][3]=0;le[8]=4;
a[9][0]=1;a[9][1]=0;a[9][2]=0;a[9][3]=1;le[9]=4;
scanf("%d",&T);
while (T--)
{
size=0;
memset(head,0,sizeof(head));
siz=1;
tr[1][0]=tr[1][1]=tag[1]=fail[1]=0;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",s);
insert(s);
}
get_fail();
dfs(root,0,tag[root]);
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
ans=0;
scanf("%s",num+1);
tot=strlen(num+1);
ans-=dp(1,root,1,1);
if (pan()) ans++;
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
scanf("%s",num+1);
tot=strlen(num+1);
ans=(ans+dp(1,root,1,1)+mod)%mod;
printf("%d\n",ans);
}
}