31. 三个袋子
【题目描述】:
平平在公园里游玩时捡到了很多小球,而且每个球都不一样。平平找遍了全身只发现了3个一模一样的袋子。他打算把这些小球都装进袋子里(袋子可以为空)。他想知道他总共有多少种放法。
将N个不同的球放到3个相同的袋子里,求放球的方案总数M。
结果可能很大,我们仅要求输出M mod K的结果。
现在,平平已经统计出了N<=10的所有情况。见下表:
N 1 2 3 4 5 6 7 8 9 10
M 1 2 5 14 41 122 356 1094 3281 9842
【输入描述】:
两个整数N,K,N表示球的个数。
【输出描述】:
输出仅包括一行,一个整数M mod K 。
【样例输入】:
11 10000
【样例输出】:
9525
【时间限制、数据范围及描述】:
时间:1s 空间:64
对于 40%数据,10<=N<=10,000
对于100%数据,10<=N<=1,000,000,000
对于 100%数据,K<=100,000.
本题是矩阵快速幂的一道有一点点变化的模板题。首先我们看一看题目中他帮你算好的规律,推出f[n]=f[n-1]*3-1。那么我们继续构建矩阵,我们可以发现,矩阵中变化的值只有f[n-1],而我们还需要保留一个不变的值-1,因此矩阵为{{3,-1},{0,1}}最后输出的时候记得把第一行的两个值加起来再输出。
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
ll mod,n;
struct jz{
ll x[5][5];
};
jz operator *(const jz &a,const jz &b){
jz c;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
c.x[i][j]=0;
for(int k=0;k<2;k++){
c.x[i][j]=(c.x[i][j]+a.x[i][k]*b.x[k][j])%mod;
}
}
}
return c;
}
jz qpow(jz m,ll n){
jz mul;mul.x[0][0]=1,mul.x[1][1]=1,mul.x[0][1]=mul.x[1][0]=0;
while(n){
if(n&1){
mul=mul*m;
}
n>>=1;
m=m*m;
}
return mul;
}
int main(){
scanf("%lld%lld",&n,&mod);
jz ans;
ans.x[0][0]=3;ans.x[0][1]=-1;ans.x[1][0]=0;ans.x[1][1]=1;
ans=qpow(ans,n-1);
printf("%lld\n",(ans.x[0][0]+ans.x[0][1]+mod)%mod);
return 0;
}