Let’s consider K-based numbers, containing exactly N digits. We define a number to be valid if its K-based notation doesn’t contain two successive zeros. For example:
- 1010230 is a valid 7-digit number;
- 1000198 is not a valid number;
- 0001235 is not a 7-digit number, it is a 4-digit number.
Given three numbers N, K and M, you are to calculate an amount of valid K based numbers, containing N digits modulo M.
You may assume that 2 ≤ N, K, M ≤ 10 18.
Input
The numbers N, K and M in decimal notation separated by the line break.
Output
The result in decimal notation.
Example
input | output |
---|---|
2 10 100 |
90 |
题解:状态转移方程:dp[1]=k-1,dp[2]=(k-1)*k,dp[i]=(k-1)*(dp[i-1]+dp[i-2])
我们设矩阵A:
k-1 k-1
1 0 为规律矩阵,即恒定矩阵。
初始矩阵B:
k-1 0
1 0
那么B[1][1]=dp[1],这里我们为了方便假设dp[0]=B[2][1]=0.
那么我们往B的左边乘上1个矩阵A得矩阵C[1][1]=dp[2],C[2][1]=dp[1].
如此迭代下去,即可得到最终结果,由于每一次都是左乘规律矩阵A,故我们可以由快速幂来优化。
快速幂理解:1次幂进来:得A*B=C,则dp[2]=C[1][1],二次幂进来得A*C=D,则dp[3]=D[1][1]……那么m-1次幂进来得到dp[m]=X[1][1].
还有由于这个版本数据比较大,则用到了矩阵快速幂的知识。
#include<iostream>
#include<cmath>
#include<cstring>
#include<stdio.h>
using namespace std;
typedef long long ll;
ll n,k,mod;
const int MOD=1e9+7;
struct Mat
{
ll mat[5][5];
void init()
{
memset(mat,0,sizeof(mat));
}
}a,b;
ll quickmul(ll a,ll b)
{
ll ans=0;
while(b)
{
if(b&1)
ans=(ans+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return ans;
}
Mat operator *(Mat a,Mat b)
{
Mat c;
memset(c.mat,0,sizeof(c.mat));
for(int i=1;i<=2;i++)
{
for(int j=1;j<=2;j++)
{
for(int k=1;k<=2;k++)
{
c.mat[i][j]=(c.mat[i][j]+quickmul(a.mat[i][k],b.mat[k][j]))%mod;
}
}
}
return c;
}
Mat quickpow(ll m) //m为1进来得到dp[2]。
{
Mat res,a;
a.init();
res.init();
res.mat[1][1]=k-1;
res.mat[2][1]=1;
a.mat[1][1]=a.mat[1][2]=k-1;
a.mat[2][1]=1;
while(m)
{
if(m&1)
res=a*res;
a=a*a;
m>>=1;
}
return res;
}
int main()
{
scanf("%lld%lld%lld",&n,&k,&mod);
Mat x=quickpow(n-1);
cout<<x.mat[1][1]<<endl;
return 0;
}
在这里也加上version1的代码吧:
#include<iostream>
using namespace std;
int main()
{
int n,k;
int dp[111];
cin>>n>>k;
dp[1]=k-1; //除了0都可选
dp[2]=(k-1)*k; //第一位除了0都可选,第二位都可选,乘法原理
for(int i=3;i<=n;i++)
dp[i]=(k-1)*(dp[i-1]+dp[i-2]);
cout<<dp[n]<<endl;
return 0;
}