AGC056B Range Argmax

Description

给定 m 个区间 [li,ri] ,求有多少个 {x1xm} 满足存在一个 1n 的排列 p 使得  i[1,m],xi=argmax{plipri}

n300

Solution

找到最小k 满足存在一个 xi=k 且所有包含 k 的区间的 xi 都是 k,这里如果任选 k 会导致重复计算

由于本题是数下标组而不是元素本身,那么可以将剩下待确定的 xi 变成子问题 [1,k),(k,n]

需要注意的是,(k,n] 这部分的子问题和原问题是完全一致的,都是要求被 [L,R] 包含的 [li,ri]xi 且没有额外的限制

但是 [1,k) 这部分需要满足所有包含 k 的元素的区间的最大值必须要是 k,也就是在 [1,k) 这个子区间选择新的 k 时要满足该元素处在全局所有包含 k 的区间的最小左端点以右,否则上一步 k 的选择是非法的

也就是说,如果预处理 mn[l][r][k] 表示所有 [l,r] 包含的 [li,ri] 中包含 k 的最小值那么 mn[l][r][k]k<k

fL,R,K 表示区间 [L,R] 的局部问题中选中的 kK 的情况下会生成多少种 xi,本质上是一个后缀和,而不对 k 加以限制的信息就可以取 fL,R,L

此时转移式便成了: fL,R,K=fL,K1,mn[L][R][K]×fK+1,R,K+1+fL,R,K+1

Code

const int N=310;
int mn[N][N][N],dp[N][N][N],n,m;
bool vis[N][N];
signed main(){
	n=read(); m=read();
	rep(i,1,m){
		int l=read(),r=read();
		vis[l][r]=1;
	}
	for(int i=n;i>=1;--i){
		for(int j=i;j<=n;++j){
			for(int k=i;k<=j;++k){
				mn[i][j][k]=k;
				if(k>=i+1) ckmin(mn[i][j][k],mn[i+1][j][k]);
				if(k<=j-1) ckmin(mn[i][j][k],mn[i][j-1][k]);
				if(vis[i][j]) mn[i][j][k]=i;
			}
		}
	}
	rep(i,0,n) dp[i+1][i][i+1]=1;
	for(int i=n;i>=1;--i){
		for(int j=i;j<=n;++j){
			for(int t=j;t>=i;--t){
				dp[i][j][t]=add(dp[i][j][t+1],mul(dp[i][t-1][mn[i][j][t]],dp[t+1][j][t+1]));
			}
		}
	}
	print(dp[1][n][1]);
	return 0;
}
posted @   没学完四大礼包不改名  阅读(194)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示