CF: *2000 比起同难度级别的题,dp可真的难做,可能是我做dp的题太少了吧。。。。
题意:
给定一个长度为n(1~ 1e5)的序列a[],其中a[i] 应该在1-200中间,但是有的值看不到了,用-1表示,
但是知道的是对于 1 < i && i < n 这样的i :a[i] <= max(a[i-1], a[i+1]) ,并且 a[1] <= a[2], a[n-1] >= a[n];
问这些不知道的数的所有的可能种数
思路:
显然是dp,状态就是每个数的值吧??
稍微做过点dp,直接想到的是 dp[i][j] 表示前i个数考虑完了,第i个数 数值为j时的所有种类数,但是考虑到状态转移(也就是i和i-1位置的种数关系),我们还要考虑一维表示当前数跟前一个数的大小关系,看似有三种关系:大于,等于,小于
其实:我们按照上述dp[i][j] 考虑的时候,输出的肯定是dp[n][] 这样的,因为规定了 a[n] <= a[n-1];所以我们可以把 <= 看作一个状态;
所以有:dp[i][j][k] ,k=1时: 前i个数已经考虑完,第i个数值为 j,且第i个数>第i-1个数 时候的所有种类数;;;;;;;;;;dp[i][j][k] ,k=0时: 前i个数已经考虑完,第i个数值为 j,且第i个数<=第i-1个数 时候的所有种类数;;;;;;;;;
对于第i个数,我们分两种情况讨论:
如果有确定值的话,假设值为x,那只要考虑dp[i][x][]就好; 求dp[i][x][1] 时:就是把前i-1个中小于x的都加上,因为此时第i个数大于第i-1个数(方程式中第二维,我们要遍历的那个数),所以 dp[i-1][t][0] 和 dp[i-1][t][1]都要加上;
而在求dp[i][x][0] 时:对于t>x,加上dp[i-1][t][0] 因为 此时第i个数小于第i-1个数,;对于t=x,加上dp[i-1][t][0]+dp[i-1][t][1];
如果此时是-1的话,那我们的第2维 j 就要考虑等于1~200的所有情况,然而按照上述求某一个数的方式复杂度看似会上去,但我们运用前缀和,后缀和的想法,遍历的时候可以把前面所有的情况算进去;
#include<bits/stdc++.h>
using namespace std;
#define out fflush(stdout);
#define fast ios::sync_with_stdio(0),cin.tie(0);
#define FI first
#define SE second
typedef long long ll;
typedef pair<ll,ll> P;
const int maxn = 1e5 + 7;
const int INF = 0x3f3f3f3f;
const ll mod = 998244353;
int n;
ll a[maxn];
ll dp[maxn][200+7][2] = {0};
// dp[i][j][k] 表示前i个数,第i个数为j时,跟前一个数大小关系为k时的最优解;k=1:>左边; k=0:<=左边
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
}
if(a[1] == -1) {
for(int j = 1; j <= 200; ++j) {
dp[1][j][1] = 1;
}
}
else {
dp[1][a[1]][1] = 1;
}
for(int i = 2; i <= n; ++i) {
if(a[i] == -1) {
ll cur = 0;
for(int j = 1; j <= 200; ++j) {
dp[i][j][1] = cur;
cur = (cur + (dp[i-1][j][1] + dp[i-1][j][0])) % mod;
}
cur = 0;
for(int j = 200; j >= 1; --j) {
cur = (cur + (dp[i-1][j][0])) % mod;
dp[i][j][0] = (dp[i-1][j][1] + cur) % mod;
}
}
else {
for(int j = 1; j < a[i]; ++j) {
dp[i][a[i]][1] = (dp[i][a[i]][1] + (dp[i-1][j][1] + dp[i-1][j][0])) % mod;
}
for(int j = 200; j >= a[i]; --j) {
dp[i][a[i]][0] = (dp[i][a[i]][0] + dp[i-1][j][0]) % mod;;
}
dp[i][a[i]][0] = (dp[i][a[i]][0] + dp[i-1][a[i]][1]) % mod;
}
}
ll ans = 0;
if(a[n] == -1) {
for(int i = 1; i <= 200; ++i) {
ans = (ans + dp[n][i][0]) % mod;
}
}
else {
ans = dp[n][a[n]][0];
}
printf("%lld\n", ans);
return 0;
}