Description
阿申准备报名参加GTGT考试,准考证号为NN位数,他不希望准考证号上出现不吉利的数字。他的不吉利数学A1A2...Am(0≤Ai≤9)A1A2...Am(0≤Ai≤9)有MM位,不出现是指中没有恰好一段等于A1A2...AmA1A2...Am.A1A1和X1X1可以为00
Input
第一行输入.接下来一行输入MM位的数
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模KK取余的结果.
Sample Input
4 3 100
111
Sample Output
81
Solution
以表示前ii个字母已经确定,没有出现过不吉利数字,且末尾与不吉利数字最多匹配了位的方案数,则答案即为∑j=0m−1dp[n][j]∑j=0m−1dp[n][j],由于已经匹配了jj位,假设要在后面加上一个数字,暴力求出此时这j+1j+1个数字与不吉利数字的最长匹配tt,只要,那么dp[i][j]dp[i][j]状态即可转移为dp[i+1][t]dp[i+1][t],以此求出dp[i]dp[i]到dp[i+1]dp[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;
}