Dessert Planning
题意:有 天,每天有上午,中午,下午,每一个时间段可以吃三种食物中的一种,但相邻时间段不能相同并且早上只能吃两种之一。给定 ,求合法吃食物方案总数。
考虑 天,每个时间段独立,所以有 个时间段,第 的时间段只能吃两种食物。
不妨设三种食物为 ,上午只能吃 和 ,那么对于任意两个相邻的上午,如果都吃 或者都吃 ,中间有两种选法,如果吃的不同,中间有 种选法。
因此可以设计 DP, 表示第 个上午吃 的方案数,令吃 时 ,吃 时 。那么 。
初始化时 。
发现这样做复杂度是 的,考虑转化成矩阵形式,。
矩阵快速幂即可,复杂度 ,注意处理最后不是上午时的结尾方案。
#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;
}
然后手玩一下发现 时 , 时 , 时 ,然后可以猜出来 ,然后就过了。

浙公网安备 33010602011771号