【AC自动机+数位DP】SDOI2014 数数

【SDOI2014】数数

【题目大意】


#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for (int i = a;i <= b;i ++)

using namespace std;

const int maxn = 1505;
const int P = (int)1e9 + 7;
int N[maxn],M,S[maxn],tot;

void read(int *x)
{
	x[0] = 0;
	static char ch;
	do ch = getchar(); while (ch < '0' || ch > '9');
	do x[++x[0]] = ch - 48, ch = getchar(); while (ch >= '0' && ch <= '9');
}

struct Node
{
	int son[10],fail;
	bool flag;
}t[maxn];

void Insert(int *s)
{
	int x = 0;
	fo(i,1,s[0])
	{
		if (!t[x].son[s[i]]) t[x].son[s[i]] = ++ tot;
		x = t[x].son[s[i]];
	}
	t[x].flag = 1;
}

void Construct_fail()
{
	static int d[maxn];
	int l = 0,r = 1;
	while (l < r)
	{
		int x = d[++l];
		fo(i,0,9)
			if (t[x].son[i])
			{
				int v = t[x].son[i];
				if (x == 0) t[v].fail = 0;
				else t[v].fail = t[t[x].fail].son[i];
				t[v].flag |= t[t[v].fail].flag;
				d[++r] = v;
			} else t[x].son[i] = t[t[x].fail].son[i];
	}
}

void Initialize()
{
	read(N);
	scanf("%d",&M);
	fo(i,1,M)
	{
		read(S);
		Insert(S);
	}
	Construct_fail();
}

int f[maxn][maxn][2];
int DP()
{
	fo(i,1,N[1]-1) 
		if (!t[t[0].son[i]].flag) f[1][t[0].son[i]][0] ++;
	if (!t[t[0].son[N[1]]].flag) f[1][t[0].son[N[1]]][1] ++;
	fo(i,1,N[0])
	{
		if (i > 1)
			fo(j,1,9) 
				if (!t[t[0].son[j]].flag) f[i][t[0].son[j]][0] ++;
		fo(j,0,tot)
		{
			if (f[i][j][0])
				fo(k,0,9)
				{
					int _j = t[j].son[k];
					if (!t[_j].flag) f[i+1][_j][0] = (f[i+1][_j][0] + f[i][j][0]) % P;
				}
			if (f[i][j][1])
			{
				fo(k,0,N[i+1]-1)
				{
					int _j = t[j].son[k];
					if (!t[_j].flag) f[i+1][_j][0] = (f[i+1][_j][0] + f[i][j][1]) % P;
				}
				int _j = t[j].son[N[i+1]];
				if (!t[_j].flag) f[i+1][_j][1] = (f[i+1][_j][1] + f[i][j][1]) % P;
			}
		}
	}
	int ret = 0;
	fo(i,0,tot) ret = ((ret + f[N[0]][i][0]) % P + f[N[0]][i][1]) % P;
	return ret;
}

int main()
{
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
	Initialize();
	printf("%d\n",DP());
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值