【学习笔记】NOIP模拟赛

32 篇文章 1 订阅
9 篇文章 0 订阅

又又又暴零了

max

原题是 AGC056B Range Argmax

这题现场也没几个人过吧。。。

考虑对于一个合法的序列 x x x,找到唯一的排列 p p p与之对应。

那么我们从 n n n开始填数,可以放置的位置是,对于所有包含这个位置的区间,其对应的 x i x_i xi都是这个位置。然后把包含这个位置的区间删去,表示后续填数不会对其造成影响。

显然不同的 x x x对应的排列 p p p是不同的,同时排列 p p p也对应一个 x x x序列,因此我们只需要计算合法的 p p p数目即可。

假设固定 p m = n p_m=n pm=n,那么相当于固定跨过 m m m的区间对应的 x x x都等于 m m m,并且左区间填的数一定都比右区间填的数大。道理很简单,因为左右区间是独立的,如果左区间没有填完,那么意味着接下来无论如何左区间都无法填满了。

对于右区间 ( m , r ] (m,r] (m,r]的计算是容易的,相当于只处理 ( m , r ] (m,r] (m,r]中所有区间的 x i x_i xi的数量,因为之前的位置都已经填满了。而对于左区间 [ l , m ) [l,m) [l,m)所有 x i x_i xi来说,不能存在一个位置,满足所有包含它的区间的 x i x_i xi都是这个位置,并且这个位置不在任意跨 m m m的区间内。

设跨 m m m区间的最左端点是 l l l,因而在去掉跨 m m m区间的限制后能填的数的位置一定 ≥ l \ge l l

基于上述观察,我们可以写出如下 d p dp dp

1.1 1.1 1.1 d p l , r , k dp_{l,r,k} dpl,r,k表示区间 [ l , r ] [l,r] [l,r]最大值位置 ≥ k \ge k k的合法 p p p序列的数目(或者说 x i x_i xi的方案数), g l , r , k g_{l,r,k} gl,r,k表示区间 [ l , r ] [l,r] [l,r]内跨 k k k的限制区间的最左端点。

1.2 1.2 1.2 有转移式 d p l , r , k = d p l , r , k + 1 + d p l , k − 1 , g l , r , k × d p k + 1 , r , k + 1 dp_{l,r,k}=dp_{l,r,k+1}+dp_{l,k-1,g_{l,r,k}}\times dp_{k+1,r,k+1} dpl,r,k=dpl,r,k+1+dpl,k1,gl,r,k×dpk+1,r,k+1

复杂度 O ( n 3 ) O(n^3) O(n3)

ps:这个 d p dp dp的确是不平凡的,或许我还没有get到大佬的脑洞??

#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define db double
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int mod=998244353;
int n,m,g[305][305][305],v[305][305];
ll dp[305][305][305];
void add(ll &x,ll y){
	x=(x+y)%mod;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);memset(g,0x3f,sizeof g);
	cin>>n>>m;for(int i=1;i<=m;i++){
		int l,r;cin>>l>>r;for(int k=l;k<=r;k++){
			g[l][r][k]=l;
		}
	}
	for(int len=2;len<=n;len++){
		for(int i=1;i<=n-len+1;i++){
			int j=i+len-1;
			for(int k=i;k<=j;k++){
				if(g[i][j][k]==0x3f3f3f3f)g[i][j][k]=min(g[i+1][j][k],g[i][j-1][k]);
			}
		}
	}for(int i=1;i<=n;i++)dp[i][i][i]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			for(int k=i;k<=j;k++){
				if(g[i][j][k]==0x3f3f3f3f)g[i][j][k]=0;
			}
		}
	}
	for(int len=2;len<=n;len++){
		for(int i=1;i<=n-len+1;i++){
			int j=i+len-1;
			for(int k=j;k>=i;k--){
				dp[i][j][k]=dp[i][j][k+1];
				if(k==j)add(dp[i][j][k],dp[i][j-1][g[i][j][j]]);
				else if(k==i)add(dp[i][j][k],dp[i+1][j][i+1]); 
				else add(dp[i][j][k],dp[i][k-1][g[i][j][k]]*dp[k+1][j][k+1]);
			}
		}
	}cout<<dp[1][n][1];
}

draw

原题是「CEOI2022」Drawing

没错这是道构造题 但我依然分毫未取233

考场上没有想到二叉树的性质怎么用。

考虑对于一般的树,把左下角的点作为根,然后极角排序划分成若干子树即可。

考场上的极限也就是 O ( n 2 ) O(n^2) O(n2)了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值