# P4910 帕秋莉的手环

Link

一句话题意:

给你一个手环,让你往里面填黑色或白色珠子,保证两个黑色不能相邻,问你有多少种填法对 \(1e9+7\) 取模的结果

题解:

一开始我以为这是一条链,写了写结果发现样例都过不去。

在回来仔细看看题,这 tm 是个环。

看到 \(n\) 的范围比较大,不用想肯定是矩阵快速幂。

\(f[i][0/1]\) 表示 \(i\) 这个位置填 白色/黑色 的方案数。

那么又转移:

  • 这一位填白色珠子的时候,上一位填黑色白色都行: \(f[i][0] = f[i-1][0] + f[i-1][1]\)

  • 这一位填黑色珠子的时候,上一位只能填白色: \(f[i][1] = f[i-1][0]\)

由于它是一个环,所以我们还要枚举一下第一个珠子的颜色。

若第一个珠子颜色为白色,则初始化为 \(f[1][0] = 1\) ,最后一位可以填黑色或者白色,对答案的贡献就是 \(f[n][0]+f[n][1]\)

若第一个珠子为黑色,则初始化 \(f[1][1] = 1\) ,最后一位只能填白色,对答案的贡献就是 \(f[n][0]\)

这样时间复杂度是 \(O(n)\) 的。

考虑矩阵快速幂加速一下。

构建转移矩阵

\[\left[ \begin{matrix} f[i-1] [0] \\ f[i-1] [1] \\ \end{matrix} \right] \tag{2} \times \left[ \begin{matrix} \ 1 &1 \\ \ 1 & 0 \\ \end{matrix} \right] = \left[ \begin{matrix} \ f[i][0] \\ \ f[i][1] \\ \end{matrix} \right] \]

直接莽上矩阵快速幂就完了。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define LL long long
LL T,n,ans;
const int p = 1e9+7;
inline LL read()
{
	LL s = 0,w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
	return s * w;
}
struct node
{
	LL a[2][2];
}st,tmp;
node operator * (node x,node y)
{
	node c;
	for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++) c.a[i][j] = 0;
	for(int i = 0; i < 2; i++)
	{
		for(int j = 0; j < 2; j++)
		{
			for(int k = 0; k < 2; k++)
			{
				c.a[i][j] = (c.a[i][j] + x.a[i][k] * y.a[k][j] % p) % p;
			}
		}
	}
	return c;
}
node operator + (node x,node y)
{
	node c;
	for(int i = 0; i < 2; i++)
	{
		for(int j = 0; j < 2; j++)
		{
			c.a[i][j] = (x.a[i][j] + y.a[i][j]) % p;
		}
	}
	return c;
}
node ksm(node a,LL b)
{
	node res;
	for(int i = 0; i < 2; i++)
	{
		for(int j = 0; j < 2; j++)
		{
			if(i == j) res.a[i][j] = 1;
			else res.a[i][j] = 0;
		}
	}
	for(; b; b >>= 1)
	{
		if(b & 1) res = res * a;
		a = a * a;
	}
	return res;
}
int main()
{
	T = read();
	while(T--)
	{
		n = read(); ans = 0;
		st.a[0][0] = 1; st.a[1][0] = st.a[1][1] = st.a[0][1] = 0;
		tmp.a[0][0] = tmp.a[0][1] = tmp.a[1][0] = 1; tmp.a[1][1] = 0;
		tmp = ksm(tmp,n-1);
		st = st * tmp;
		ans = (st.a[0][0] + st.a[0][1]) % p;
		st.a[0][1] = 1; st.a[0][0] = st.a[1][0] = st.a[1][1] = 0;
		st = st * tmp;
		ans = (ans + st.a[0][0]) % p;
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2020-09-29 07:58  genshy  阅读(104)  评论(0编辑  收藏  举报