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;
}
posted @ 2026-06-21 22:57  kzssCCC  阅读(2)  评论(0)    收藏  举报