刷题记录:牛客NC20875舔狗舔到最后一无所有

传送门:牛客

题目描述:

作为队伍的核心,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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值