美丽序列

题意

福克斯喜欢整数序列,他认为一个序列美丽的定义是

1.每个数都在\(0\)\(40\)之间

2.每个数都小于等于之前的数的平均值

具体地说:

for each \(i,1\le i<N,A[i]\le (A[0]+A[1]+...+A[i-1])/i\).

3.没有三个连续的递减的数

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

输入格式

第一行输入一个整数\(n(1\le n\le 40)\)

第二行输入\(n\)个整数

输出格式

输出一个整数

样例输入1

2
3 -1

样例输出1

4

样例输入2

3
5 3 -1

样例输出2

2

样例输入3

3
-1 0 40

样例输出3

0

样例输入4

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

样例输出4

579347890

样例输入5

6
-1 12 25 0 18 -1

样例输出5

58

分析

不想贪心,暴力dp即可。

因为数据范围极小,所以开四维dp数组,\(dp[i][last][len][sum]\)表示第\(i\)个数是\(last\),前\(i\)个数组成的序列末尾的递减序列长度为\(len\),前\(i\)个数的和为\(sum\),则转移方程:(前缀\(new\)表示当前状态,不加表示上一个状态)

\(if\;i>1\;then\{\)

\(if\;a[i]!=-1\;then\)

\(dp[i][a[i]][2][newsum]=\sum dp[i-1][last][1][sum]\)

\(dp[i][a[i]][1][newsum]=\sum dp[i-1][last][2][sum]+\sum dp[i-1][last][1][sum]\)

\(else\)

\(dp[i][newlast][2][newsum]=\sum dp[i-1][last][1][sum]\)

\(dp[i][newlast][1][newsum]=\sum dp[i-1][last][2][sum]+\sum dp[i-1][last][1][sum]\)

\(\}\)

\(else\{\)

\(if\;a[1]!=-1\;then\)

\(dp[1][a[1]][1][a[1]]=1\)

\(else\)

\(dp[1][last][1][last]=1\)

\(\}\)

Code

#include<cstdio>
#define maxn 45
#define mod 1000000007ll
#define PE(x,y) x=((x)+(y))%mod
using namespace std;//dp[i][num_at_the_end][length_of_decreasing_sequence][sum]
int a[maxn],n;
long long dp[maxn][maxn][3][1605];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&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++){
        if(a[i]!=-1){
            for(int sum=a[i]*(i-1);sum<=1600-a[i];sum++){
                int newsum=sum+a[i];
                for(int last=0;last<=40;last++){
                    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;
        }
        for(int newlast=0;newlast<=40;newlast++){
            for(int sum=newlast*(i-1);sum<=1600-a[i];sum++){
                int newsum=sum+newlast;
                for(int last=0;last<=40;last++){
                    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(int sum=0;sum<=1600;sum++){
        for(int last=0;last<=40;last++){
            for(int len=1;len<=2;len++){
                PE(ans,dp[n][last][len][sum]);
            }
        }
    }
    printf("%lld",ans);
    return 0;
}

启示:dp是除爆搜以外最暴力的算法……

猜你喜欢

转载自www.cnblogs.com/BlogOfchc1234567890/p/9862075.html