传送门:牛客
题目描述:
作为队伍的核心,forever97很受另外两个队友的尊敬。
Trote_w每天都要请forever97吃外卖,但很不幸的是宇宙中心forever97所在的学校周围只有3家forever97爱吃的外卖。
如果Trote_w给forever97买了别家的外卖,forever97就会大喊“我不吃我不吃”。
但是forever97又不喜欢连续三天吃一种外卖。
如果Trote_w哪天忘了这件事并且三天给他买了同一家外卖,那么forever97就会把Trote_w的头摁进手机屏幕里。
作为Trote_w的好朋友,你能告诉他连续请forever97吃n天饭,有多少不同的购买方法吗?
输入:
2
3
500
输出:
24
544984352
[题外话]:标题好评!!!
对于这道题,emmm,应该是能看出来是一道dp题的,接下来的问题就是如何推出我们的dp方程了.
我们仔细的分析一下题意就能发现前后是存在关系的:
我们假设dp[i][j]
代表第j天吃第i中外卖的总方法(包括前面的)
那么对于第j-1
来说存在两种情况,假设我们的第j-1
天是和第j
天一样的,那么第j-2
天肯定就不能和其一样了,那么假设此时i=0
,此时我们就有dp[1][j-2]+dp[2][j-2]
中方法
假设我们的第j-1
天与我们的第j
天并不是一样的,那么贡献就是dp[1][j-1]+dp[2][j-1]
即可,因为第三天不需要管前面的情况
所以我们就可以得到这样的一个dp方程:
dp[0][j]=dp[1][j-2]+dp[2][j-2]+dp[1][j-1]+dp[2][j-1]
接下来直接递推即可,注意边界
一维数组优化:在我们的推理过程中我们还会发现其实在第j天吃任何食物的种类数是一样的,因此我们可以将其压缩成一维,但是对于这道题不优化照样能过,下面就不给出优化代码了
注意需要使用long long和取模
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
#include <deque>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x = 0, w = 1;
char ch = getchar();
for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') w = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps = 1e-8;
int T;
ll dp[4][100010];
const int mod=1e9+7;
int main() {
memset(dp, 0, sizeof(dp));
dp[0][0] = dp[1][0] = dp[2][0] = 0;
dp[0][1] = dp[1][1] = dp[2][1] = 1;
dp[0][2] = dp[1][2] = dp[2][2] = 3;
for(int i=3;i<=100000;i++) {
dp[0][i]=(dp[1][i-2]+dp[2][i-2]+dp[1][i-1]+dp[2][i-1])%mod;
dp[1][i]=(dp[0][i-2]+dp[2][i-2]+dp[0][i-1]+dp[2][i-1])%mod;
dp[2][i]=(dp[0][i-2]+dp[1][i-2]+dp[0][i-1]+dp[1][i-1])%mod;
}
T=read();int num;
for(int i=1;i<=T;i++) {
num=read();
cout<<(dp[0][num]%mod+dp[1][num]%mod+dp[2][num]%mod)%mod<<endl;
}
return 0;
}