CF2144E1 思路分享(dp)
https://codeforces.com/problemset/problem/2144/E1
题意概述
\(n\) 座塔从左到右排列,高度为 \(a_i\),记 \(L(a)\) 为从左看依次能看见的塔的高度,\(R(a)\) 为从右看依次能看见的塔的高度,求满足 \(L(a)=L(a')\) 且 \(R(a)=R(a')\) 的 \(a'\) 数量,其中 \(a'\) 是 \(a\) 的子序列,模 \(998244353\).
\(1\le n \le 5000\).
思路
只考虑左边,考虑 \(dp\),记 \(dp1[i][j]\) 为 \(a\) 中前 \(i\) 个元素能匹配 \(L(a)\) 的前 \(j\) 个元素的方案数,讨论每个位置选或不选转移即可.
类似地处理右边,记为 \(dp2\).
考虑如何整合,发现只需关注最大值位置,枚举左边最大值第一次出现位置 \(p\) 和右边最大值第一次出现位置 \(q\),将两边方案数相乘,中间数任选.
为了刻画最大值第一次出现,需要一些处理,记 \(len=|idx|\),\(m_1=|L(a)|\),\(m_2=|R(a)|\), 具体地,总贡献为:
\[\sum_{i=0}^{len}{\sum_{j=i}^{len}{dp1[idx[i]-1][m_1-1] \cdot dp2[idx[j]+1][m_2-1] \cdot 2^{\max(0,idx[j]-idx[i]-1)}}}
\]
时间复杂度 \(\mathcal{O}(n^2)\).
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MOD = 998244353;
const int INF = 1e9;
ll qpow(ll a,ll b){
ll res = 1;
while (b){
if (b&1){
res = res*a%MOD;
}
a = a*a%MOD;
b >>= 1;
}
return res;
}
void solve(){
int n;
cin >> n;
vector<int> a(n+1);
for (int i=1;i<=n;i++){
cin >> a[i];
}
int pre = 0;
vector<int> temp{0};
for (int i=1;i<=n;i++){
pre = max(pre,a[i]);
temp.push_back(pre);
}
sort(temp.begin()+1,temp.end());
temp.erase(unique(temp.begin()+1,temp.end()),temp.end());
int m = temp.size()-1;
vector<vector<ll>> dp(n+1,vector<ll>(m+1));
dp[0][0] = 1;
for (int i=1;i<=n;i++){
dp[i] = dp[i-1];
for (int j=0;j<=m;j++){
if (a[i]<=temp[j]){
dp[i][j] = (dp[i][j]+dp[i-1][j])%MOD;
}
else if (j+1<=m && a[i]==temp[j+1]){
dp[i][j+1] = (dp[i][j+1]+dp[i-1][j])%MOD;
}
}
}
int suf = 0;
temp.clear();
temp.push_back(0);
for (int i=n;i>=1;i--){
suf = max(suf,a[i]);
temp.push_back(suf);
}
sort(temp.begin()+1,temp.end());
temp.erase(unique(temp.begin()+1,temp.end()),temp.end());
int m2 = temp.size()-1;
vector<vector<ll>> dp2(n+2,vector<ll>(m2+1));
dp2[n+1][0] = 1;
for (int i=n;i>=1;i--){
dp2[i] = dp2[i+1];
for (int j=0;j<=m2;j++){
if (a[i]<=temp[j]){
dp2[i][j] = (dp2[i][j]+dp2[i+1][j])%MOD;
}
else if (j+1<=m2 && a[i]==temp[j+1]){
dp2[i][j+1] = (dp2[i][j+1]+dp2[i+1][j])%MOD;
}
}
}
int mx = temp.back();
vector<int> idx;
for (int i=1;i<=n;i++){
if (a[i]==mx){
idx.push_back(i);
}
}
int len = idx.size();
ll res = 0;
for (int i=0;i<len;i++){
for (int j=i;j<len;j++){
res = (res+dp[idx[i]-1][m-1]*dp2[idx[j]+1][m2-1]%MOD*qpow(2,max(0,idx[j]-idx[i]-1))%MOD)%MOD;
}
}
cout << res << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号