#dp#L 最多变的序列

题目

小 E 拥有一个 \(n\) 的全排列序列 \(a_i\)。ta 可以进行操作,一次操作形如:选择一个子区间 \(a[l..r]\),将这个区间内的所有数替换为它们的最小值,

小 E 想问你,进行任意次这样的操作(可以一次也不操作),能得到多少种不同的序列。你只需要求这个值对 \(998244353\) 取模的结果即可。


分析

对于序列中某个值 \(c\) 出现的位置,⼀定是连续的⼀段区间 \([l,r]\)。且这个区间原本的最小值恰好为 \(c\)。针对这样合法的序列统计,只需要从左到右考虑当前 \(a_i\) 能覆盖的⼀段区间即可。

\(dp[i][j]\) 表示前 \(i\) 个数,第 \(i\) 个位置被某个值覆盖时右端点的位置,那么就是求出 \(a_i\) 覆盖的范围,那么在 \([l,r]\) 之间如果选择 \(a[i]\) 作为最小值,那么,\(dp[i][j]+=dp[i-1][j-1]\),当然 \(dp[i][j]\) 可以来自 \(dp[i-1][j]\)


代码

#include <iostream>
#include <algorithm>
using namespace std;
int Test,n,dp[3011],a[3011];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	for (cin>>Test;Test;--Test){
		cin>>n;
		for (int i=1;i<=n;++i) cin>>a[i];
		dp[0]=1;
		for (int i=1;i<=n;++i){
			int l=i,r=i;
			while (l>=1&&a[l]>=a[i]) --l;
			while (r<=n&&a[r]>=a[i]) ++r;
			for (int j=l+1;j<r;++j) dp[j]=(dp[j]+dp[j-1])%998244353;
		}
		cout<<dp[n];
		for (int i=0;i<=n;++i) dp[i]=0;
	}
	return 0;
}
posted @ 2025-08-12 08:26  lemondinosaur  阅读(48)  评论(0)    收藏  举报