题目链接:http://codeforces.com/contest/1068/problem/D
题意:
给你n个数,其中有一些数字被遗忘了(被遗忘的数输入位-1),但是知道所有的数满足:a1≤a2,an≤an−1 同时对所有的2~n-1种的数满足 ai≤max(ai−1,ai+1),问给你的数有多少种正确的填法。
做法:
感觉上好像是要用dp的,但是参考了大佬的博客,菜知道了这道题dp的含义。大概就是三维,dp[2][203][3]代表的是到达第i个数时,在确实这个数为j的情况下,它左边的那个数小于/等于/大于它时候的方法数。
转移方程让我想了很久吧,尤其是第三维的操作,当等于的时候,只要把左边那个数方法发012都加上即可(因为是左边那个数在确定为j的情况下的方法数,而这个数当前要等于它,所以直接加),而小于的时候,因为是从1for到200的,所以只要存一个前缀和,在处理之前把数进行赋值,再相加即可(即如果这个数确定为5,那么sum当前还未加前保存的是左边的数为1234所有方法的总和),再另外,如果是大于的话同理,但是要从200for到1,另外还要注意,如果是大于的话不要加上所有的,起码左边那个数的小于不能加,因为这样会不符合题意(这里是为什么,我现在脑子还有点糊。。)。大概就是这样吧。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int maxn=100005;
ll dp[2][205][3];
//0为小于 1为等于 2为大于
ll n,a[maxn];
int main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
int p=0;
for(int i=1;i<=200;i++){
if(a[1]==-1||a[1]==i)
dp[p][i][0]=1;
}
for(int i=2;i<=n;i++){
for(int j=1;j<=200;j++){
if(a[i]==-1||a[i]==j)
dp[p^1][j][1]=(dp[p][j][0]+dp[p][j][1]+dp[p][j][2])%mod;
else dp[p^1][j][1]=0;
}
ll sum=0;
for(int j=1;j<=200;j++){
if(a[i]==-1||a[i]==j)
dp[p^1][j][0]=sum;
else dp[p^1][j][0]=0;
sum=(sum+dp[p][j][0]+dp[p][j][1]+dp[p][j][2])%mod;
}
sum=0;
for(int j=200;j>=1;j--){
if(a[i]==-1||a[i]==j)
dp[p^1][j][2]=sum;
else dp[p^1][j][2]=0;
sum=(sum+dp[p][j][1]+dp[p][j][2])%mod;
}
p^=1;
}
ll ans=0;
for(int i=1;i<=200;i++){
ans=(ans+dp[p][i][1]+dp[p][i][2])%mod;
}
printf("%lld\n",ans);
return 0;
}