您的位置:首页 > 其它

【NOIP2017提高A组模拟8.23】密码

2017-08-23 18:40 429 查看

Description:



题解:

这肯定是数位dp,十分显然。

首先对n个串建一个AC自动机,这样我们就可以表示出当前dp的状态了。

设fi,j,k,0/1表示从高往低已经确定了前i个位,匹配数为j,包含当前第i位的后缀走到了AC自动机的第j位,是否顶满。

转移就相当于在AC自动机通过fail跳,预处理一下就行了。

可以维护一个数组表示在AC自动机上的第i个点,这个点代表的字符串的所有后缀包含多少个密匙,需要注意更新顺序需要和fail指针一样。

Code:

#include<cstdio>
#include<cstring>
#define ll long long
#define fo(i, x, y) for(ll i = x; i <= y; i ++)
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;

const ll mo = 1e9 + 7;
ll n, k, len, a[505], m, ans;
char s[505], s2[505], s3[505];
ll root = 1, tot = 1, next[1000][10], fail[1000], sum[1000], up[1000];
ll d[1005];
ll f[1005][12][500][2];
ll zf[500][12];

void Init() {
scanf("%lld %lld", &n, &k);
scanf("%s", s + 1); scanf("%s", s2 + 1);
fo(i, 1, n) {
scanf("%s", s3 + 1);
len = strlen(s3 + 1);
ll k = root;
fo(j, 1, len) {
if(!next[k][s3[j] - 48]) next[k][s3[j] - 48] = ++ tot;
k = next[k][s3[j] - 48];
}
sum[k] ++;
}
}

void Build_ac() {
fail[root] = 0;
d[1] = root;
for(ll st = 1, en = 1; st <= en; st ++) {
ll x = d[st];
fo(i, 0, 9) if(next[x][i]) {
ll y = next[x][i], j = fail[x];
while(j != 0 && !next[j][i])
j = fail[j];
fail[y] = next[j][i]; if(fail[y] == 0) fail[y] = root;
d[++ en] = y;
}
}
fo(i, 1, tot) {
ll j = i;
while(j != root) {
up[i] += sum[j]; j = fail[j];
}
}
}

void Build() {
fo(j, 1, tot) {
fo(num, 0, 9) {
ll g = j;
while(g != root && !next[g][num])
g = fail[g];
if(next[g][num]) g = next[g][num];
zf[j][num] = g;
}
}
}
void Do() {
memset(f, 0, sizeof(f));
f[0][0][root][1] = 1;
fo(i, 1, m) {
fo(j, 1, tot) {
fo(num, 0, 9) {
ll p = zf[j][num];
fo(u, 0, k) f[i][min(k, u + up[p])][p][0] += f[i - 1][u][j][0];
}
}
fo(j, 1, tot) {
fo(num, 0, a[i] - 1) {
ll p = zf[j][num];
fo(u, 0, k) f[i][min(k, u + up[p])][p][0] += f[i - 1][u][j][1];
}
}
fo(j, 1, tot) {
ll num = a[i];
ll p = zf[j][num];
fo(u, 0, k) f[i][min(k, u + up[p])][p][1] += f[i - 1][u][j][1];
}
fo(j, 1, tot) fo(u, 0, k) f[i][u][j][0] %= mo, f[i][u][j][1] %= mo;
}
fo(j, 1, tot)
ans += f[m][k][j][0] + f[m][k][j][1], ans %= mo;
}

int main() {
freopen("word.in", "r",  stdin);
freopen("word.out", "w",  stdout);
Init();
Build_ac();
Build();
m = strlen(s + 1);
fo(i, 1, m) a[i] = s[i] - 48;
Do();
ans = -ans;
m = strlen(s2 + 1);
fo(i, 1, m) a[i] = s2[i] - 48;
Do();
ans = (ans % mo + mo) % mo;
printf("%lld\n", ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: