1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1416 Solved: 851
[ Submit][ Status]
Description
阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为0
Input
第一行输入N,M,K.接下来一行输入M位的数。 100%数据N<=10^9,M<=20,K<=1000 40%数据N<=1000 10%数据N<=6
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
Sample Input
111
Sample Output
HINT
Source
题意:有一个有n位的学号,每个位是0~9的任意一个数,给出一个长度为m的串,问n位的学号有多少种情况是子串中不含那个长度为m的串。
思路:我们的状态可以表示为当前匹配到那个m串的什么位置,然后转移的时候是根据下一个是0~9的哪一个就对应的转移到了匹配m串的什么位置。 所以这里我们能用KMP算出m串的失败指针,然后再算出假设插入0~9中的其中一个,看某个位置能转移到哪个位置,假设是从i转移到了j,那么我们在矩阵的(i,j)处+1,表示 i可以转移到 j。由于n非常大,所以直接递推是不实际的。 我们把状态做成一个1*(M+1)的矩阵,设为A,对应的(0,i) 的数字表示当前匹配了m串的0~i-1 的有多少个串。 然后转移的关系也是一个矩阵 大小是(M+1)*(M+1), 设为B,AxB其实表示的就是n串的长度为1的时候的状态,如果在乘一次B,那么就是长度为2的时候的状态,所以长度为n的时候就是Ax(B)^n , 那么这里我们就能用矩阵快速幂来处理了。 最后的话得到的是一个1*(m+1)的矩阵,我们只需要把0~(m-1)列的数加起来,就是题目要求的数了
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
#define LL long long
char s[25];
int f[25];
LL n, m, mod;
int A[25][25];
void getFail()
{
f[0] = 0; f[1] = 0;
for (int i = 1; i < m; ++i) {
int j = f[i];
while (j&&s[i] != s[j]) j = f[j];
f[i + 1] = s[i] == s[j] ? j + 1 : 0;
}
}
void getMatrix()
{
memset(A, 0, sizeof(A));
for (int i = 0; i < m; ++i) {
for (char j = '0'; j <= '9'; ++j) {
int k = i;
while (k&&s[k] != j) k = f[k];
if (s[k] == j) ++k;
++A[i][k];
}
}
A[m][m] = 10;
}
void Multiple(int M1[25][25], int n1, int m1, int M2[25][25], int n2, int m2)
{
int ret[25][25];
memset(ret, 0, sizeof(ret));
for (int i = 0; i < n1;++i)
for (int j = 0; j < m2; ++j)
for (int k = 0; k < m1; ++k)
ret[i][j] = (ret[i][j]+M1[i][k] * M2[k][j])%mod;
memcpy(M1, ret, sizeof(ret));
}
void qpow(int M[25][25],int n, int p)
{
int ret[25][25];
memset(ret, 0, sizeof(ret));
for (int i = 0; i < n; ++i) ret[i][i] = 1;
while (p>0) {
if (p & 1) Multiple(ret, n, n, M, n, n);
Multiple(M, n, n, M, n, n);
p >>= 1;
}
memcpy(M, ret, sizeof(ret));
}
void solve()
{
getFail();
getMatrix();
qpow(A, m + 1, n);
int B[25][25];
memset(B, 0, sizeof(B));
B[0][0] = 1;
Multiple(B, 1, m + 1, A, m + 1, m + 1);
int sum = 0;
for (int i = 0; i < m; ++i)
sum = (sum + B[0][i]) % mod;
printf("%d\n", sum);
}
int main()
{
while (scanf("%lld%lld%lld", &n, &m, &mod) == 3)
{
scanf("%s",s);
solve();
}
}