Description
阿申准备报名参加 GT G T 考试,准考证号为 N N 位数,他不希望准考证号上出现不吉利的数字。他的不吉利数学 A1A2...Am(0≤Ai≤9) A 1 A 2... A m ( 0 ≤ A i ≤ 9 ) 有 M M 位,不出现是指中没有恰好一段等于 A1A2...Am A 1 A 2... A m . A1 A 1 和 X1 X 1 可以为 0 0
Input
第一行输入.接下来一行输入 M M 位的数
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模 K K 取余的结果.
Sample Input
4 3 100
111
Sample Output
81
Solution
以表示前 i i 个字母已经确定,没有出现过不吉利数字,且末尾与不吉利数字最多匹配了位的方案数,则答案即为 ∑j=0m−1dp[n][j] ∑ j = 0 m − 1 d p [ n ] [ j ] ,由于已经匹配了 j j 位,假设要在后面加上一个数字,暴力求出此时这 j+1 j + 1 个数字与不吉利数字的最长匹配 t t ,只要,那么 dp[i][j] d p [ i ] [ j ] 状态即可转移为 dp[i+1][t] d p [ i + 1 ] [ t ] ,以此求出 dp[i] d p [ i ] 到 dp[i+1] d p [ i + 1 ] 的转移矩阵,矩阵快速幂加速转移即可
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef int M[22][22];
int n,m,mod;
char s[22];
void Mul(M &A,M B)
{
M C;
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
{
C[i][j]=0;
for(int k=0;k<m;k++)C[i][j]=(C[i][j]+A[i][k]*B[k][j])%mod;
}
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
A[i][j]=C[i][j];
}
void Pow(M &A,int k)
{
M C;
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
C[i][j]=(i==j);
while(k)
{
if(k&1)Mul(C,A);
Mul(A,A);
k>>=1;
}
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
A[i][j]=C[i][j];
}
int main()
{
scanf("%d%d%d%s",&n,&m,&mod,s+1);
M A;
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
A[i][j]=0;
for(int j=0;j<m;j++)
for(int k=0;k<=9;k++)
{
int i=j+1;
for(;i>=1;i--)
if(s[i]-'0'==k)
{
int flag=1;
for(int l=1;l<i;l++)
if(s[i-l]!=s[j-l+1])
{
flag=0;
break;
}
if(flag)break;
}
if(i!=m)A[i][j]++;
}
Pow(A,n);
int ans=0;
for(int i=0;i<m;i++)ans=(ans+A[i][0])%mod;
printf("%d\n",ans);
return 0;
}