牛客-美丽序列

题目描述

牛牛喜欢整数序列,他认为一个序列美丽的定义是
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个整数

输出描述:

输出一个整数

示例1

输入

2
3 -1

输出

4

示例2

输入

3
5 3 -1

输出

2

示例3

输入

3
-1 0 40

输出

0

示例4

输入

11
-1 40 -1 -1 -1 10 -1 -1 -1 21 -1

输出

579347890

备注:

子任务1: n <= 10
子任务2: n <= 20
子任务3: 无限制

解题思路 

看了好多别人的题解,都是在说动态规划,

主要思路就是说定义一个四维的数组dp[i][last][len][sum],其表示第i个数是last,前i个数组成的序列末尾的递减序列长度为len,前i个数的和为sum,用来存储在这种情况下美丽序列的个数,然后把整数序列从前往后判断,有点类似于子序列问题,根据前面的状况来推出下一步的情况,并且给出状态转移方程:(前缀newnew表示当前状态,不加表示上一个状态)

 一开始我也看不懂,但其实可以换一个角度思考问题,既然我用一个数组dp[i][last][len][sum]来表示在当前情况下美丽序列的个数,其中last、len、sum是不确定的,那就直接枚举每一种情况暴力得到结果(我个人认为有时候动态规划和暴力的思想是差不多的,从一种状态转移到另一种状态,状态之间有许多种可能(本题的可能性为-1能变成那些值),则枚举每一种可能)

核心代码

遍历到整数序列的第i位时,判断dp[i][last][len][sum],其中last、len、sum有多种可能性,直接用for循环嵌套暴力枚举每一种可能性,for循环之间的顺序不重要,只是对last、len、sum的所有可能性进行暴力枚举而已,顺序变化不会影响最终结果(前缀newnew表示当前状态,不加表示上一个状态)

#include<bits/stdc++.h>
#define maxn 45
#define mod 1000000007
#define PE(x,y) x=(x+y)%mod
using namespace std;
int a[maxn],n;//存储整数序列
long long dp[maxn][maxn][3][1605];
//dp[i][last][len][sum]表示第i个数是last,前i个数组成的序列末尾的递减序列长度为len,前i个数的和为sum
//用来表示可能的情况



	for(int i=2;i<=n;i++){
        //分-1和不是-1的情况讨论
		if(a[i]!=-1){//确定性
				for(int last=0;last<=40;last++){//前一位的可能性
                   for(int sum=a[i]*(i-1);sum<=40*i-a[i];sum++){//由定义2可以推出前面所有数的和的范围
				        int newsum=sum+a[i];
					    if(a[i]<last){
                            PE(dp[i][a[i]][2][newsum],dp[i-1][last][1][sum]);}
					    else{
				            PE(dp[i][a[i]][1][newsum],dp[i-1][last][2][sum]);
                            PE(dp[i][a[i]][1][newsum],dp[i-1][last][1][sum]);}
				}
			}
			continue;//代替了else的作用
		}
		for(int newlast=0;newlast<=40;newlast++){//不确定性
            for(int last=0;last<=40;last++){
                	for(int sum=newlast*(i-1);sum<=40*i-a[i];sum++){//由定义2可以推出前面所有数的和的范围
				        int newsum=sum+newlast;
					    if(newlast<last){
                            PE(dp[i][newlast][2][newsum],dp[i-1][last][1][sum]);}
					    else{
				            PE(dp[i][newlast][1][newsum],dp[i-1][last][2][sum]);
				            PE(dp[i][newlast][1][newsum],dp[i-1][last][1][sum]);}
				}
			}
		}
	}

先确定好当前第i位相关last、len、sum的值,然后判断前一位的所有可能的情况中有多少种满足条件,满足就加1,然后再变换第i位相关last、len、sum的值,重复上一步

题解代码

#include<bits/stdc++.h>
#define maxn 45
#define mod 1000000007
#define PE(x,y) x=(x+y)%mod
using namespace std;
int a[maxn],n;//存储整数序列
long long dp[maxn][maxn][3][1605];
//dp[i][last][len][sum]表示第i个数是last,前i个数组成的序列末尾的递减序列长度为len,前i个数的和为sum
//用来表示可能的情况
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    ///关闭输入输出流
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];}
	if(a[1]!=-1)dp[1][a[1]][1][a[1]]=1;
	else{
		for(int last=0;last<=40;last++){
			dp[1][last][1][last]=1;}
	}
	for(int i=2;i<=n;i++){
        //分-1和不是-1的情况讨论
		if(a[i]!=-1){//确定性
				for(int last=0;last<=40;last++){//前一位的可能性
                   for(int sum=a[i]*(i-1);sum<=40*i-a[i];sum++){//由定义2可以推出前面所有数的和的范围
				        int newsum=sum+a[i];
					    if(a[i]<last){
                            PE(dp[i][a[i]][2][newsum],dp[i-1][last][1][sum]);}
					    else{
				            PE(dp[i][a[i]][1][newsum],dp[i-1][last][2][sum]);
                            PE(dp[i][a[i]][1][newsum],dp[i-1][last][1][sum]);}
				}
			}
			continue;//代替了else的作用
		}
		for(int newlast=0;newlast<=40;newlast++){//不确定性
            for(int last=0;last<=40;last++){
                	for(int sum=newlast*(i-1);sum<=40*i-a[i];sum++){//由定义2可以推出前面所有数的和的范围
				        int newsum=sum+newlast;
					    if(newlast<last){
                            PE(dp[i][newlast][2][newsum],dp[i-1][last][1][sum]);}
					    else{
				            PE(dp[i][newlast][1][newsum],dp[i-1][last][2][sum]);
				            PE(dp[i][newlast][1][newsum],dp[i-1][last][1][sum]);}
				}
			}
		}
	}
	long long ans=0;
    //三个for循环的顺序无关,没有影响
    for(int len=1;len<=2;len++){
        for(int last=0;last<=40;last++){ 
            for(int sum=0;sum<=1600;sum++){
				PE(ans,dp[n][last][len][sum]);}
		}
	}
	cout<<ans<<endl;
	return 0;
}

题目思路我可能写的有点绕,但主要的点就是-1在美丽序列定义的限制下会有多种可能,对dp[i][last][len][sum]造成的影响就是last、len、sum的不确定性,那就枚举last、len、sum的每一种情况来判断有多少种符合条件的美丽序列,如果有没看懂的地方可以评论或者给我私信,我看到了就会回复。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值