HDU 6030 Happy Necklace(矩阵快速幂)

21 篇文章 0 订阅

思路:

1.我们用r表示红色,用b表示蓝色,对于一串长为s的珠子,它的末尾情况一共会有三种:(1)***b(2)***br(3)***brr(其中第三种包括了b在离末尾更远的地方),我们设这三个情况的种数分别为a,b,c
2.此时这串珠子在情况(1)只能继续加红色珠子,得到长度为s+1的情况(2)的珠子;原珠子在情况(2)也只能继续加红色珠子,得到长度为s+1的情况(3)的珠子;原珠子在情况三则可以加红珠子和蓝珠子,分别得到长度为s+1的情况(3)和情况(1)的珠子;
3.因此对于情况为(1)(2)(3)、种数分别为a、b、c、长度为s的串,递推到长度为s+1之后,这串珠子三种情况的长度分别为c、a、b+c,由此我们可以得到递推矩阵
[ 0 0 1 1 0 0 0 1 1 ] ∗ [ a b c ] = [ c a b + c ] \left[ \begin{matrix} 0 & 0 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 1 \end{matrix} \right]* \left[ \begin{matrix} a \\ b \\ c \end{matrix} \right]= \left[ \begin{matrix} c \\ a \\ b+c \end{matrix} \right] 010001101abc=cab+c
4.最后利用矩阵快速幂算一下递推矩阵的n-2次幂,就可以直接从原始矩阵递推到长度为n的珠子对应的 3 ∗ 1 3*1 31矩阵啦,最后将三种情况加起来就可以了;
(PS:如果这题一直超时,大家不妨换成g++编译器提交一发)

代码:

#include<iostream>
#include<vector>
using namespace std;
template <class T> inline void read(T &res){
	char c;do{c=getchar();}while(c<'0'||c>'9');
	res=c-'0';while(c=getchar(),c>='0'&&c<='9') res=res*10+(c-'0');
}
inline void out(int x){if(x>9) out(x/10); putchar(x%10+'0');}
typedef long long LL;
typedef vector<int> vec;
typedef vector<vec> mat;
const int M=1e9+7;
mat mul(mat &A,mat & B){
	mat C(3,vec(3));
	for(int i=0;i<3;i++)
	for(int k=0;k<3;k++)
	for(int j=0;j<3;j++)
	C[i][j]=(C[i][j]+1ll*A[i][k]*B[k][j]%M)%M;
	return C;
}
mat Pow(mat A,LL n){
	mat B(3,vec(3));
	for(int i=0;i<3;i++) B[i][i]=1;
	while(n>0){
		if(n&1) B=mul(B,A);
		A=mul(A,A);
		n>>=1;
	}
	return B;
}
LL n;
mat A={{0,0,1},{1,0,0},{0,1,1}};
void solve(){
	read(n);
	mat B=Pow(A,n-2);
	int ans=0;
	for(int i=0;i<3;i++) for(int j=0;j<3;j++) ans=(ans+B[i][j])%M;
	out(ans); putchar('\n');
}
int main(){
	int t; read(t);
	while(t--) solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值