※bzoj1009

来源:互联网 发布:合肥淘宝客服招聘兼职 编辑:程序博客网 时间:2024/05/16 19:37

这题真心是挺难的!!!至少看solution前是这样的。

题目的n到10的9次方,应该是要给它加个log才行。

坦白说我的第一感觉以为这是一道字符串题。BUT!我字符串学的比较差,也没继续想。

现在给出解法:

首先是最神的dp函数定义:f[i][j]表示——匹配到主串的第i位为止(长的叫主串,短的叫模式串,这个是KMP算法里给出的定义),恰匹配上了模式串的第j位的总可能数。

接下来再给出一个二维数组b[i][j]。假如现在,前i位匹配成功,再加上一个数字,变成了匹配到第j位。对于这一组(i,j),有多少个数字能满足这个性质呢?b[i][j]存储的就是这个数目。

于是,有方程如下。


再说说矩阵加速——把b[i][j]整个倒过来,即转成b[j][i],初值矩阵乘n次b矩阵,就是包含答案的矩阵了。

上代码——

#include <cstdio>char str[25]; int n, m, mod, next[25], b[25][25], a[25][25];//b[j][i]表示str的0~i-1位再加上一位后,得到的新串的后缀和str的前缀的最长公共部分的长度变为j。这样的数有多少个 //是的,就是b[j][i],我没写反inline void KMP() {next[1] = 0;int j = next[1];for(int i = 2; i <= m; i++){while(j && str[j + 1] != str[i]) j = next[j];if(str[j + 1] == str[i]) ++j;next[i] = j;}for(int i = 0; i < m; ++i)for(int j = 0; j <= 9; ++j) {int t = i;while(t && str[t + 1] - '0' != j) t = next[t];if(str[t + 1] - '0' == j) ++t;if(t != m) b[t][i] = (b[t][i] + 1) % mod;}return ;}inline void mul(int a[25][25], int b[25][25], int ans[25][25]) {int tmp[25][25];for(int i = 0; i < m; ++i)for(int j = 0; j < m; ++j) {tmp[i][j] = 0;for(int k = 0; k < m; ++k)tmp[i][j] = (tmp[i][j] + a[i][k] * b[k][j]) % mod;}for(int i = 0; i < m; ++i)for(int j = 0; j < m; ++j)ans[i][j] = tmp[i][j];return ;}inline void test() {for(int i = 0; i < m; ++i) {for(int j = 0; j < m; ++j) printf("b[%d][%d]=%d  ", j, i, b[i][j]);printf("\n");}return ;}int main() {scanf("%d%d%d", &n, &m, &mod);scanf("%s", str+1);KMP();//test();for(int i = 0; i < m; ++i) a[i][i] = 1;while(n) {if(n & 1) mul(a, b, a);mul(b, b, b);n>>= 1;}int sum = 0;for(int i = 0; i < m; ++i)sum = (sum + a[i][0]) % mod;printf("%d", sum);return 0;}


原创粉丝点击