P4910题解

思路貌似跟dalao们的有点不一样

先前排声明一下,蒟蒻刚学OI没多久,而且是自学的,所以思路可能比较sb+累赘

大致题意


给一串珠子,每个珠子黑白两种颜色,而且两个珠子中一定要有一个白色的珠子,求方案总数


思路

既然每种珠子都有两种颜色,我们先假定前一个珠子是黑色的,那么后一个珠子就必须是白色(两个珠子中一定要有一个白色珠子) 如果是白色的,那就可以有黑,白两种选择,画成图的话大概就是这个样子

图中所示为n=5的时候的情况

很明显可以看出n=5的所有可能是从n=3和n=4过来的

可以得出递推式

(a_{n} =a_{n-1}+a_{n-2})

当然这个递推式显然是不对的,应为题目中给出的是一个环,所以要减去开头结尾均为黑色的所有可能

观察一下不难发现开头结尾均为黑色的可能为n-2的所有结尾为黑色的可能

我们这里设(b_{n})为记录每个数字结尾为黑色的个数

根据之前的递推式

可以发现(b_{n} =b_{n-3}+b_{n-4}) (左右二分)

当n=1和n=2时(b_{n})均为0 可以直接去掉

(b_{n} =b_{n-1}+b_{n-2})

那么就可以得到最终的递推式了

(f_{n} =a_{n-1}-b_{n-1}+a_{n-2}-b_{n-2}=a_{n}-b_{n}=f_{n-1}+f_{n-2})

(egin{cases}1(n=1)\3 (n=2)\f_{n} =f_{n-1}+f_{n-2}(n>=3)end{cases})

然后再套矩阵快速幂的模板就可以了

贴上丑陋不堪的辣鸡代码

#include<bits/stdc++.h>
using namespace std;
int mo=1000000007;
long long n,t;
struct matrix{
	long long int a[5][5];
}ans,a;
matrix operator *(const matrix &x,const matrix &y){
	matrix z;
	for(int i=1;i<=2;i++){
		for(int j=1;j<=2;j++){
			z.a[i][j]=0;
		}
	}
	for(int k=1;k<=2;k++){
		for(int i=1;i<=2;i++){
			for(int j=1;j<=2;j++){
				z.a[i][j]=(z.a[i][j]+(x.a[i][k]*y.a[k][j])%mo)%mo;
			}
		}
	}
	return z;
}
int main(){
	cin>>t;
	while(t--){
		cin>>n;
		if(n==1){
			cout<<1<<endl;
		}
		
	else if(n==2){
		cout<<3<<endl;
	}
	else{
		for(int i=1;i<=3;i++){
				for(int j=1;j<=3;j++){
					a.a[i][j]=0;
					if(i==j) ans.a[i][j]=1;
					else ans.a[i][j]=0;
				}
			}
		a.a[1][2]=a.a[2][2]=a.a[2][1]=1;
		a.a[1][1]=0;
		n-=1;
		while(n){
			if(n&1) ans=ans*a;
			n>>=1;
			a=a*a;
		}
		cout<<(1*ans.a[1][1]+3*ans.a[1][2])%mo<<endl;
	}
	
	}
	return 0;
}
原文地址:https://www.cnblogs.com/xcxc82/p/13339548.html