04 UOJ(WHYZ)P31 三个袋子 递推+矩阵快速幂

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;
}

猜你喜欢

转载自blog.csdn.net/jialiang2509/article/details/80382423