动态规划
——牛客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个整数
输出描述:
输出一个整数
示例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][j][flag][sum] 表示当第i个数时,如果这个数时j,flag他和前面的数是否构成数组降序(1就是前面没有降序,2就是和前一个构成降序,题目中不超过三个降序),sum就是前面i-1个数的综合(所以这个数的循环从j*(i-1)开始循环,使得这个数要大于前面数的平均值)
(做完这个题目还是比较开心的,这个看完题解后到AC时间比较短,感觉自己还是有进步的,不然这多维数我肯定直接起步就放弃了)
#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
typedef long long ll;
ll dp[50][50][3][1605];
int n,a[50];
int main()
{
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
memset(dp,0,sizeof(dp));
if(a[1]==-1)
{
for(int i=0; i<=40; i++)
dp[1][i][1][i]=1;
}
else
dp[1][a[1]][1][a[1]]=1;
for(int i=2; i<=n; i++)
if(a[i]==-1)
for(int j=0; j<=40; j++)
for(int k=0; k<=40; k++)
for(int sum=j*(i-1); sum<=1600-j; sum++)
if(j>=k)
{
dp[i][j][1][sum+j]+=(dp[i-1][k][1][sum]+dp[i-1][k][2][sum])%mod;
dp[i][j][1][sum+j]%=mod;
}
else
{
dp[i][j][2][sum+j]+=dp[i-1][k][1][sum];
dp[i][j][2][sum+j]%=mod;
}
else
{
int j=a[i];
for(int k=0; k<=40; k++)
for(int sum=j*(i-1); sum<=1600-j; sum++)
if(j>=k)
{
dp[i][j][1][sum+j]+=(dp[i-1][k][1][sum]+dp[i-1][k][2][sum])%mod;
dp[i][j][1][sum+j]%=mod;
}
else
{
dp[i][j][2][sum+j]+=dp[i-1][k][1][sum];
dp[i][j][2][sum+j]%=mod;
}
}
ll ans=0;
for(int j=0;j<=40;j++)
for(int sum=j*n;sum<=1600;sum++)
{
ans+=dp[n][j][1][sum]+dp[n][j][2][sum];
ans%=mod;
}
printf("%lld\n",ans);
}
}