【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); }
相关文章推荐
- 【JZOJ5332】【NOIP2017提高A组模拟8.23】密码
- 【jzoj5332】【NOIP2017提高A组模拟8.23】【密码】【ac自动机】【动态规划】
- 【NOIP2017提高A组模拟8.22】密码
- 5332. 【NOIP2017提高A组模拟8.23】密码 AC自动机+数位DP
- 【NOIP2017提高A组模拟10.5】Ping
- 【NOIP2017提高A组模拟10.10】总结
- JZOJ 100035【NOIP2017提高A组模拟7.10】区间
- 【NOIP2017提高组模拟12.18】A
- 【NOIP2017提高A组模拟8.16】最短路
- NOIP2017提高组模拟赛 9 (总结)
- NOIP2017提高组模拟19 /10.31
- 【NOIP2017提高A组模拟9.7】简单无向图 dp
- 【NOIP2017提高组模拟12.10】幻魔皇
- 【NOIP2017提高组模拟12.18】B
- 【NOIP2017提高组模拟12.17】环
- 【NOIP2017提高组模拟12.17】向再见说再见
- 【NOIP2017提高组模拟12.24】C
- 【NOIP2017提高A组模拟7.8】为了爱情 八数码拓展
- 【NOIP2017提高组模拟12.10】神炎皇
- 【NOIP2017提高组模拟6.25】总结