Day2 – 美丽序列

1.题目描述

链接:https://ac.nowcoder.com/acm/problem/21313

牛牛喜欢整数序列,他认为一个序列美丽的定义是
1:每个数都在0到40之间
2:每个数都小于等于之前的数的平均值
具体地说:for each i, 1 <= i < N,  A[i] <= (A[0] + A[1] + … + A[i-1]) / i.
3:没有三个连续的递减的数

现在给你一个序列,每个元素是-1到40,你可以将序列中的-1修改成任意的数,求你可以得到多少个美丽序列,答案对1e9+7取模

输入描述

第一行输入一个整数n (1 ≤ n ≤ 40)
第二行输入n个整数

输出描述

输出一个整数

2.示例

输入:

3
5 3 -1

输出:

2

3.思路分析

我们注意到数字的状态和题目条件:

  1. 对于第i个数,可能取值为 j (numbers[i] 为-1的话),每个数在0-40之间,因此  0<=j<=40;
  2. 没有三个连续的递减的数,因此第i个数只有可能是第一个递减的数或者第二个递减的数(否则不存在美丽序列),因此可以用一个k来表示递减的状态(也就是第几个)
  3. 每个数要小于等于之前数的平均值,因此需要对前面数的和/均值进行记录和判断

结合上述的分析,可以设计动态规划数组:dp[i][j][k][sum]表示第i个位置,取值为 j 时,递减状态为k,和为sum的方案数

k只能取值为 1 或者 2

初始化

初始化的时候对第一个number进行判断即可,如果第一个number为 -1,遍历初始化dp[0][j][1][j] = 1; 其中 0<=j<=40;否则直接初始化dp[0][number][1][number] = 1;

那么状态转移如下:

1.当numbers[i]不为-1的时候,对递减进行判断

如果当前的值大于上一个值(numbers[i] >= lj):

dp[i][numbers[i]][1][sum+numbers[i]] += dp[i-1][lj][1][sum]+dp[i-1][lj][2][sum];

sum为前i-1个数字的和,lj为上一个数字的值(last j)

否则,

dp[i][numbers[i]][2][sum+numbers[i]] += dp[i-1][j][1][sum];

2.当numbers[i]为-1的时候,我们只需要对j进行遍历,和lj进行比较即可(多加一层循环)

如果 当前取的j值大于上一个值 (j>= lj ):

dp[i][j][1][sum+j] += dp[i-1][lj][1][sum]+dp[i-1][lj][2][sum];

否则,

dp[i][j][2][sum+j] = dp[i-1][lj][1][sum];

4.代码实现

#include<iostream>
#include<vector>
using namespace std;


//dp[i][j][k][sum]表示第i个位置的数为j时,递减为第k位,总和为sum的方案数
//dp[i][j][k][sum]
long long dp[41][41][3][1601];
int numbers[40];
const int MOD = 1e9 + 7;

int main()
{

	int n;
	cin >> n;
	for (int i = 0; i < n; ++i)
		cin >> numbers[i];
	//初始化dp数组
	if (numbers[0] == -1)
	{
		for (int j = 0; j <= 40; ++j)
			dp[0][j][1][j] = 1;
	}
	else
	{
		dp[0][numbers[0]][1][numbers[0]] = 1;
	}
	//进行状态转移
	for (int i = 1; i < n; ++i)
	{
		if (numbers[i] == -1)
		{
			//枚举这个-1可能取得的值
			for (int j = 0; j <= 40; ++j)
			{
				//枚举上一个数
				for (int lj = 0; lj <= 40; ++lj)
				{
					//枚举之前的和,大于平均值
					for (int s = j * i; s <= 40 * i; ++s)
					{
						if (j >= lj)
						{
							dp[i][j][1][s + j] += dp[i - 1][lj][1][s] + dp[i - 1][lj][2][s];
							dp[i][j][1][s + j] %= MOD;
						}
						else
						{
							dp[i][j][2][s + j] += dp[i - 1][lj][1][s];
							dp[i][j][2][s + j] %= MOD;
						}
					}
				}
			}
		}
		else
		{
			//枚举上一个数,可能是 0-40 中的一位
			for (int lj = 0; lj <= 40; ++lj)  
			{
				//枚举之前的和,满足大于平均值
				for (int s = numbers[i] * i; s <= 40 * i; ++s)
				{
					if (numbers[i] >= lj)
					{
						dp[i][numbers[i]][1][s + numbers[i]] += dp[i - 1][lj][1][s] + dp[i - 1][lj][2][s];
						dp[i][numbers[i]][1][s + numbers[i]] %= MOD;
					}
					else
					{
						dp[i][numbers[i]][2][s + numbers[i]] += dp[i - 1][lj][1][s];
						dp[i][numbers[i]][2][s + numbers[i]] %= MOD;
					}
				}
			}
		}
	}
	//查找答案
	long long res = 0;
	for (int j = 0; j <= 40; ++j)
	{
		for (int s = j * n; s <= 1600; ++s)
		{
			res = res + dp[n-1][j][1][s] + dp[n-1][j][2][s];
			res %= MOD;
		}
	}
	printf("%lld", res);

	return 0;
}

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇