【学习笔记】NOIP模拟赛

又又又暴零了

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)了。


__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530080.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(26)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示