Dessert Planning

题意:有 nn 天,每天有上午,中午,下午,每一个时间段可以吃三种食物中的一种,但相邻时间段不能相同并且早上只能吃两种之一。给定 nn,求合法吃食物方案总数。

考虑 nn 天,每个时间段独立,所以有 3n3n 个时间段,第 1,4,7,1,4,7,\cdots 的时间段只能吃两种食物。

不妨设三种食物为 a,b,ca,b,c,上午只能吃 aabb,那么对于任意两个相邻的上午,如果都吃 aa 或者都吃 bb,中间有两种选法,如果吃的不同,中间有 33 种选法。

因此可以设计 DP,dpi,jdp_{i,j} 表示第 ii 个上午吃 jj 的方案数,令吃 aaj=1j=1,吃 bbj=2j=2。那么 {dpi,1=dpi1,1×2+dpi1,2×3dpi,2=dpi1,2×2+dpi1,1×3\begin{cases} dp_{i,1} = dp_{i-1,1} \times2 + dp_{i-1,2} \times 3 \\ dp_{i,2} = dp_{i-1,2} \times 2 + dp_{i-1,1} \times 3\end{cases}

初始化时 dp1,1=dp1,2=1dp_{1,1} = dp_{1,2} = 1

发现这样做复杂度是 O(n)O(n) 的,考虑转化成矩阵形式,[dpi,1dpi,2]=[dpi1,1dpi1,2]×[2332]\begin{bmatrix} dp_{i,1} & dp_{i,2} \end{bmatrix} = \begin{bmatrix} dp_{i-1,1} & dp_{i-1,2} \end{bmatrix} \times \begin{bmatrix}2 & 3 \\ 3 & 2 \end{bmatrix}

矩阵快速幂即可,复杂度 O(logn)O(\log n),注意处理最后不是上午时的结尾方案。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;

const int N = 1e5 + 5;

const long long MOD = 1e9 + 7;
long long n;

// dp[i][j]:第i个早上选j方案数
// dp[i][a] = dp[i - 1][a] * 2 + dp[i - 1][b] * 3
// dp[i][b] = dp[i - 1][b] * 2 + dp[i - 1][a] * 3

struct Matrix
{
	long long a[3][3];
	Matrix operator*(const Matrix& g) const
	{
		Matrix c;
		for (int i = 1; i < 3; i++)
		{
			for (int j = 1; j < 3; j++)
			{
				c.a[i][j] = 0;
				for (int k = 1; k < 3; k++) c.a[i][j] = (c.a[i][j] + a[i][k] * g.a[k][j] % MOD) % MOD;
			}
		}
		return c;
	}
};

Matrix qpow(Matrix x, long long y)
{
	Matrix ans = x, base = x;
	y--;
	while (y)
	{
		if (y & 1)
		{
			ans = ans * base;
		}
		base = base * base;
		y >>= 1;
	}
	return ans;
}
long long dp[3][4];

int main()
{
	scanf("%lld", &n);
	n *= 3;
	if (n == 3)
	{
		printf("%lld\n", 8);
		return 0;
	}
	long long x = n;
	while (n % 3 != 1)
	{
		n--;
	}
	long long cnt = (n - 1) / 3;
	Matrix p;
	p.a[1][1] = p.a[2][2] = 2;
	p.a[1][2] = p.a[2][1] = 3;
	Matrix res = qpow(p, cnt);
	Matrix h;
	h.a[1][1] = 1;
	h.a[1][2] = 1;
	res = h * res;
	long long cnta = res.a[1][1], cntb = res.a[1][2];
	dp[1][1] = cntb;
	dp[1][2] = cnta;
	dp[1][3] = (cnta + cntb) % MOD;
	dp[2][1] = (dp[1][2] + dp[1][3]) % MOD;
	dp[2][2] = (dp[1][1] + dp[1][3]) % MOD;
	dp[2][3] = (dp[1][1] + dp[1][2]) % MOD;
	printf("%lld\n", (dp[2][1] + dp[2][2] + dp[2][3]) % MOD);
	return 0;
}

然后手玩一下发现 n=1n=1ans=8ans=8n=2n=2ans=40ans=40n=3n=3ans=200ans=200,然后可以猜出来 ans=8×5n1ans=8 \times 5^{n-1},然后就过了。

posted @   HappyBobb  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示