首页 > 其他分享 >【2023.11.13】NOIP2023模拟试题-33.md

【2023.11.13】NOIP2023模拟试题-33.md

时间:2023-11-13 21:22:48浏览次数:37  
标签:md 13 填补 33 tr times int 待定 节点

T1

贪心地找到和最大的组的较大数删除是最优选择,因此开线段树维护全局最大数,并单点更新指定位置的值。

参考代码

展开代码
#include<bits/stdc++.h>
using namespace std;
#define fi(l,r) for(int i=l;i<=r;++i)
#define ff(i,l,r) for(int i=l;i<=r;++i)
#define ll long long
#define ly __int128
#define lp ll
#define lson(x) ((x)<<1)
#define rson(x) (lson(x)|1)
#define Lson(x) tr[lson(x)]
#define Rson(x) tr[rson(x)]
#define mod %P
#define N 500005
struct Info{
	int sum,pos;
	bool operator < (const Info b)const{return sum<b.sum;}
};
int n,m,tid,a[N],nxt[N],pre[N];
struct node{int l,r,sum,mxi;}tr[N*30];//全局查询+单点修改最大的 a[mxi]+a[nxt[mxi]]
#define valof(x) (a[x]+a[nxt[x]])
void pushup(int x){
	if(tr[x].l==tr[x].r)tr[x].mxi=tr[x].l;
	else{
		if(valof(Lson(x).mxi)>valof(Rson(x).mxi))tr[x].mxi=Lson(x).mxi;
		else tr[x].mxi=Rson(x).mxi;
	}
	return;
}
void build(int x,int l,int r){
	tr[x].l=l,tr[x].r=r;
	if(l==r){
		tr[x].sum=a[l],tr[x].mxi=l;
		return;
	}
	int mid=(l+r)>>1;
	build(lson(x),l,mid);
	build(rson(x),mid+1,r);
	pushup(x);
	return;
}
void update(int x,int pos){
	if(tr[x].l==tr[x].r){
		tr[x].sum=a[pos];
		return;
	}
	if(pos<Rson(x).l)update(lson(x),pos);
	else update(rson(x),pos);
	pushup(x);
	return;
}
int main(){
	freopen("necklace.in","r",stdin);
	freopen("necklace.out","w",stdout);
	scanf("%d %d %d",&tid,&n,&m);
	fi(1,n){
		nxt[i]=i+1;pre[i]=i-1;
		scanf("%d",&a[i]);
	}
	nxt[n]=1,pre[1]=n;
	build(1,1,n);
	ff(t,1,n-m){
		int x=tr[1].mxi;
		if(a[x]<a[nxt[x]])x=nxt[x];//找到和最大的一对里面值最大的一个
		nxt[pre[x]]=nxt[x];
		pre[nxt[x]]=pre[x];
		a[x]=0;//删除这个点
		update(1,x);
		update(1,pre[x]);
	}
	printf("%d",valof(tr[1].mxi));
	return 0;
}

T2

啊 $\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $ 又是计数 dp 题

我们先考虑问题的弱化版:儿子的个数在 \([l_i,r_i]\) 之间,并且儿子序号的最值 \(k_i > i\)

如果是这样的话,我们只需要开一个二维 dp \(f[i][j]\) 代表 第 \(i\) 到第 \(n\) 个点组成了 \(j\) 棵树的的组合方式。那么我们从 \(n\) 往 \(1\) 的每个节点的加入其实就是从子树往根节点构建树,也就是新增一条链或者给子树当根节点的过程(因为倒序,所以一定是根节点)。那么就有

\[\forall l \in [l_i,r_i] \Rightarrow \begin{cases} f[i-1][j+1]&+=f[i][j] &,\;l=0 &\;\;\text{( 新增链 )} \\ f[i-1][j]&+=f[i][j] &,\;l=1 &\text{( 新增一颗子树根节点 )} \\ f[i-1][j-1]&+=f[i][j] &,\;l=2 &\text{( 新增两个子树的共同根节点 )} \end{cases} \]

为什么要从子树往根构建而不从根往子树构建呢?

因为考虑所有子树,我们只需要枚举根节点,

而若考虑所有根节点,我们就需要枚举子树。

显然枚举根节点更方便。

接下来我们考虑题目的限制条件。题目更改的条件是

如果第 \(i\) 个节点不为叶子,那么其儿子的最大编号 \(k_i > i\)

其实就是从子树往根构建的过程中,除了新建子树以外,还可以添加到子树的非根节点上作为子树的子树。但是我们要从 \(1\) 到 \(n\) 顺序枚举,所以不用考虑成为根节点的情况(不然不能保证子节点与父节点的大小关系)

因此,我们只需要新记录一维需要填补的空缺儿子位置个数 \(k\) 就可以了。当我们从 \(1\) 到 \(n\) 顺序枚举的时候,显然,待定节点的序号一定大于父亲节点。对于 \(\forall l \in [l_i,r_i]\),我们分类讨论,只需要保证 \(l=1\) 与 \(2\) 的节点要有待定子节点就行了 :

若 \(l=0\)

显然只能当做新子树或者子树的子树。

因此:

\(f[i+1][j+1][k]+=f[i][j][k]\) ( 新建根节点 )

1

\(f[i+1][j][k-1]+=f[i][j][k]\times k\) ( 填补 \(k\) 个待定位中的任意一个 )

2

若 \(l=1\)

显然可能新增左或右 \(2\) 种待定节点。

因此:

\(f[i+1][j][k]+=f[i][j][k] \times 2\) ( 根节点 + 创建左或右待定子节点 )

3

\(f[i+1][j][k-1]+=f[i][j][k]\times k\times 2\) ( 填补待定位 + 创建待定子节点 )

4

若 \(l=2\)

显然可能会新增 \(1\) 种待定节点。

\(f[i+1][j+1][k+2]+=f[i][j][k]\) ( 根节点 + 创建待定子节点 )

5

\(f[i+1][j][k+1]+=f[i][j][k]\times k\) ( 填补根节点 + 创建待定子节点 )

6

\(f[i+1][j-1][k]+=f[i][j][k]\times (j-1) \times k \times 2\) ( 填补待定点 + 引入(所填补的待定点所在链以外)任意一条不保证序号大于自己的链放于左或右儿子 + 创建待定点 )

7

\(f[i+1][j][k+1]+=f[i][j][k]\times j \times 2\) ( 引入任意链 + 创建待定点 )

8

参考代码

/*
  bug:1.还要钦定这个节点下方待补节点的左右位置
 */
#include<bits/stdc++.h>
using namespace std;
#define fi(l,r) for(int i=l;i<=r;++i)
#define ff(i,l,r) for(int i=l;i<=r;++i)
#define ll long long
#define ly __int128
#define lp ll
#define lson(x) ((x)<<1)
#define rson(x) (lson(x)|1)
#define Lson(x) tr[lson(x)]
#define Rson(x) tr[rson(x)]
#define mod %P
#define P 1000000007
#define N 305
int tid,T,n,ql[N],qr[N];
ll f[N][N][N<<1];
void work(){
	memset(f,0,sizeof f);
	scanf("%d",&n);
	fi(1,n)scanf("%d %d",&ql[i],&qr[i]);
	f[0][0][0]=1;											//别忘了初始化
	fi(0,n-1){
		ff(j,0,i){
			ff(k,0,i<<1){
				if(f[i][j][k]==0)continue;
				f[i][j][k]%=P;
				if(ql[i+1]==0){
					f[i+1][j+1][k]+=f[i][j][k];				//新建根节点
					if(k)f[i+1][j][k-1]+=f[i][j][k]*k;		//填补k个待定位中的任意一个
				}
				if(ql[i+1]<=1&&qr[i+1]>=1){
					f[i+1][j+1][k+1]+=f[i][j][k]*2;			//根节点 + 创建左或右待定子节点	//bug #1 : 同时还要钦定这个节点下的待补节点位置
					f[i+1][j][k]+=f[i][j][k]*k*2;			//填补待定位 + 创建待定子节点
				}
				if(qr[i+1]==2){
					f[i+1][j+1][k+2]+=f[i][j][k];			//根节点+创建待定子节点
					f[i+1][j][k+1]+=f[i][j][k]*k;			//填补根节点+创建待定子节点
					if(j)f[i+1][j-1][k]+=f[i][j][k]*(j-1)*k*2;//填补待定点 + 引入(所填补的待定点所在链以外)任意一条不保证序号大于自己的链放于左或右儿子 + 创建待定点
					f[i+1][j][k+1]+=f[i][j][k]*j*2;			//引入任意链 + 创建待定点
				}
			}
		}
	}
	printf("%lld\n",f[n][1][0]%P);							//点统毕,只单链,无待定点
	return;
}
int main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	scanf("%d %d",&tid,&T);
	while(T-->0)work();
	return 0;
}

T3 T4

什么?T3 T4 是我能到达的地方吗?

标签:md,13,填补,33,tr,times,int,待定,节点
From: https://www.cnblogs.com/DZhearMins/p/17830224.html

相关文章

  • 11.13
    ......
  • 11.13算法
    题目二叉搜索树中第K小的元素给定一个二叉搜索树的根节点root,和一个整数k,请你设计一个算法查找其中第 k 个最小元素(从1开始计数)。示例1:输入:root=[3,1,4,null,2],k=1输出:1示例2:输入:root=[5,3,6,2,4,null,null,1],k=3输出:3提示:树中的节点数为n。......
  • 每日总结11.13
    外观模式1、理解外观模式的动机,掌握该模式的结构;2、能够利用外观模式解决实际问题。实验任务:计算机开启在计算机主机(Mainframe)中,只需要按下主机的开机按钮(on()),即可调用其他硬件设备和软件的启动方法,如内存(Memory)的自检(check())、CPU的运行(run())、硬盘(HardDisk)的读取(......
  • Linux p13 压缩和解压指令
    压缩和解压指令gzip/gunzip指令gzip:用于压缩文件gunzip:用于解压的基本语法:gzip文件,压缩文件,只能将文件压缩为.gz文件。gunzip文件.gz,解压缩文件命令。zip/unzip指令zip:用于压缩文件unzip:用于解压文件,这个在项目打包中很有用。基本语法:zip[选项]xxx.zip......
  • OpenSSL学习(Secure Socket Layer)2023/11/13
    示例OpenSSL版本为OpenSSL3.0.215Mar2022(Library:OpenSSL3.0.215Mar2022)别搞错了!搞错容易在sm2签名验签出问题生成自签名证书opensslreq-x509-newkeyrsa:2048-keyoutmykey.pem-outmycert.pem-days365req:表示进行证书请求和生成。-x509:表示生成自......
  • 每日总结11.13
    今天参加了分级测试,找到了有关自己的很多问题和薄弱之处,同时也学到了一点东西,三小时并没有写出来什么好东西,我觉得jsp不太好用,但是springboot应用的也不太熟练,还是因为自己不太熟练,除此之外,在收到题目之后我没有理清思路,以为自己没看完题目就直接做可以快点做完,结果却发现思路不明......
  • 11.13测试总结
    测试中出现了一些没有见过的错误,又调试了半天,在引入mysql数据库时的一些细节问题得到了解决,对整体结构的构造更加清晰,并且学习到了一些新知识,可以在同一界面中放置不同角色的因素,然后不同的角色对应不同的元素展示,进而减少工作量,同时在此次测试中也暴露了一些问题,对项目的整体结......
  • 11.13
    今天在建民老师的自评测试中,我深刻认识到了自己的不足。之前我尝试做了上学期期末考试的试题,但仅仅用了大约4个小时的时间完成了三个表的增删改查,而且连深层的业务逻辑如审批都没有尝试。我只获得了期末考试一半左右的分数,这说明我在增删改查的练习上还有很大的不足。在今天的考试......
  • Windows系统CMD命令行添加或删除路由
    Windows系统CMD命令行添加或删除路由 原文地址:https://www.cnblogs.com/dianchaozhang/p/16985395.html1,按Win键输入“CMD”,右键“以管理员身份运行” 2,在CMD窗口输入“ipconfig”并按Enter键  3,找到自己的网卡对应的“默认网关”,执行如下命令添加路由: routeadd{......
  • 11.13
    T1很有意思的贪心。显然只有四种情况:\(a\)为\(1/2\),\(b\)为\(1/2\)。那么为这四种情况分别记录一个\(vector\)。我们记录\(suma\)为\(a\)的总和,\(sumb\)为\(b\)的总和。那么显然我们需要让这个分配方式达到\(suma/2\)和\(sumb/2\)。考虑贪心,先将两个都卡在同......