题目传送门
感觉这个题的dp不是很好想(牛客的题目怎么都这么鬼畜的说?)
需要开一个四维dp数组
dp[i][j][k][m]意思就是第i个数字为j的而且连续k个单调递减的和为m的美丽序列的个数。
其中代码实现还是非常考验人的。
其实状态转移真的不难想,但是主要是要开一个四维数组这个不容易想到。
#include<iostream>
using namespace std;
typedef long long ll;
ll dp[42][42][3][1601];
ll a[210];
const ll modd=1e9+7;
int main(){
ll n;
cin>>n;
for(ll i=1;i<=n;i++)cin>>a[i];
if(a[1]==-1)//我第一个我就不确定
{
for(ll i=0;i<=40;i++){
dp[1][i][1][i]=1;
}
}else dp[1][a[1]][1][a[1]]=1;
for(ll i=2;i<=n;i++){
if(a[i]==-1){
for(ll j=0;j<=40;j++){//枚举本位数字
for(ll p=0;p<=40;p++){//枚举上一个数字
for(ll k=j*(i-1);k<=1600-j;k++)//因为可能a[1]是-1因此只能浪费一定的时间
{
//这么枚举的好处就是能够将j>sum的情况筛去
if(j>=p){
dp[i][j][1][k+j]+=dp[i-1][p][1][k]+dp[i-1][p][2][k];
dp[i][j][1][k+j]=dp[i][j][1][k+j]%modd;
}else{
dp[i][j][2][k+j]+=dp[i-1][p][1][k];
dp[i][j][2][k+j]=dp[i][j][2][k+j]%modd;
}
}
}
}
}else{
for(ll p=0;p<=40;p++){//不用枚举本位数字了
for(ll k=a[i]*(i-1);k<=1600-a[i];k++){
if(a[i]>=p){
dp[i][a[i]][1][k+a[i]]+=dp[i-1][p][1][k]+dp[i-1][p][2][k];
dp[i][a[i]][1][k+a[i]]=dp[i][a[i]][1][k+a[i]]%modd;
}else{
dp[i][a[i]][2][k+a[i]]+=dp[i-1][p][1][k];
dp[i][a[i]][2][k+a[i]]=dp[i][a[i]][2][k+a[i]]%modd;
}
}
}
}
}
ll ans=0;
for(ll i=0;i<=40;i++){
for(ll k=0;k<=1600;k++){
ans+=dp[n][i][1][k];
ans=ans%modd;
ans+=dp[n][i][2][k];
ans=ans%modd;
}
}
cout<<ans<<endl;
}