Codeforces 1067A - Array Without Local Maximums 計數dp+詳細推導 (Codeforces Round #518 (Div. 1))
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;
}