首页 > 其他分享 >csp-s模拟11

csp-s模拟11

时间:2024-10-14 18:00:56浏览次数:1  
标签:11 rt int lim ll fa csp 模拟 rson

csp-s模拟11

\(T1\) T2203. 玩水 (water) \(100pts\)

  • 定义一个点 \((i,j)\) 是分点当且仅当 \(s_{i,j+1}=s_{i+1,j}\) ,而一个点 \((i,j)\) 是合点当且仅当 \((i-1,j-1)\) 是分点。

  • 先考虑若只有两个人时,只要存在一个分点就一定有解。

  • 扩展到三个人时,若存在一个合点可以通过向右或向下走到达另外一个分点或存在两个相邻的分点就一定有解,于是就转化为了二维偏序问题,因 \(n,m \le 1000\) 故二维前缀和维护即可。

    点击查看代码
    int sum[1010][1010],vis[1010][1010];
    char c[1010][1010];
    int main()
    {
    	freopen("water.in","r",stdin);
    	freopen("water.out","w",stdout);
    	int t,n,m,flag,i,j,k;
    	cin>>t;
    	for(k=1;k<=t;k++)
    	{
    		flag=0;
    		cin>>n>>m;
    		for(i=1;i<=n;i++)
    		{
    			for(j=1;j<=m;j++)
    			{
    				cin>>c[i][j];
    			}
    		}
    		for(i=1;i<=n;i++)
    		{
    			for(j=1;j<=m;j++)
    			{
    				vis[i][j]=(i+1<=n&&j+1<=m&&c[i+1][j]==c[i][j+1]);
    				sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+vis[i][j];
    				flag|=(vis[i][j]==1&&(vis[i-1][j]==1||vis[i][j-1]==1||sum[i-1][j-1]>=1));
    			}
    		}
    		cout<<flag<<endl;
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T2\) T2212. AVL 树 \(20pts\)

  • 部分分

    • \(20pts\) :爆搜。
    点击查看代码
    int ch[500010][2],fa[500010],vis[500010],h[500010];
    vector<int>ans,tmp;
    bool cmp(vector<int>a,vector<int>b)
    {
    	if(a.size()<b.size())
    	{
    		return false;
    	}
    	for(int i=0;i<a.size();i++)
    	{
    		if(a[i]>b[i])
    		{
    			return false;
    		}
    		if(a[i]<b[i])
    		{
    			return true;
    		}
    	}
    	return false;
    }
    void print(int x)
    {
    	if(x==0||vis[x]==0)
    	{
    		return;
    	}
    	h[x]=1;
    	print(ch[x][0]);
    	tmp.push_back(x);
    	print(ch[x][1]);
    	h[x]+=max(h[ch[x][0]],h[ch[x][1]]);
    }
    void dfs(int pos,int n,int k,int rt)
    {
    	if(pos==n+1)
    	{
    		if(k==0)
    		{
    			int flag=1;
    			for(int i=1;i<=n;i++)
    			{
    				if(vis[i]==1)
    				{
    					flag&=vis[fa[i]];
    				}
    			}
    			if(flag==1)
    			{
    				tmp.clear();
    				memset(h,0,sizeof(h));
    				print(rt); 
    				for(int i=1;i<=n;i++)
    				{
    					if(vis[i]==1)
    					{
    						flag&=(abs(h[ch[i][0]]-h[ch[i][1]])<=1);
    					}
    				}
    				if(flag==1&&cmp(ans,tmp)==false)
    				{
    					ans=tmp;
    				}
    			}
    		}
    	}
    	else
    	{
    		if(k>=1)
    		{
    			vis[pos]=1;
    			dfs(pos+1,n,k-1,rt);
    		}
    		if(pos!=rt)
    		{
    			vis[pos]=0;
    			dfs(pos+1,n,k,rt);
    		}
    	}
    }
    int main()
    {
    	freopen("avl.in","r",stdin);
    	freopen("avl.out","w",stdout);
    	int n,k,rt=0,i;
    	cin>>n>>k;
    	for(i=1;i<=n;i++)
    	{
    		cin>>fa[i];
    		if(fa[i]==-1)
    		{
    			fa[i]=0;
    			rt=i;
    		}
    		else
    		{
    			ch[fa[i]][fa[i]<i]=i;
    		}
    	}
    	vis[0]=1;
    	dfs(1,n,k,rt);
    	memset(vis,0,sizeof(vis));
    	for(i=0;i<ans.size();i++)
    	{
    		vis[ans[i]]=1;
    	}
    	for(i=1;i<=n;i++)
    	{
    		cout<<vis[i];
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 正解

    • 左根右的中序遍历在删除整棵子树的情况下,贪心策略为尽可能多地选择左子树的点,优先递归左子树。
    • 考虑如何判断当前节点是否可以保留。回溯它的祖先节点直至根,对于该节点是左儿子的情况计算出保留这个节点至少需要右子树中有多少个节点。若剩下的 \(k\) 足够,那么就可以保留。
      • 预处理 \(f_{i}\) 表示高度为 \(i\) 的 AVL 树所包含的最少节点数量,递推式为 \(f_{i}=\begin{cases} 1 & i=1 \\ 2 & i=2 \\ f_{i-1}+f_{i-2}+1 & i>2 \end{cases}\) 。
    • 同时还需要保证删完后的树是一棵平衡树,故左儿子不能选太多的点。设 \(h_{x}\) 表示以 \(x\) 为根的子树内的最大深度, \(used_{x}\) 表示以 \(x\) 为根的子树内的已经选择过的最大深度, \(lim_{x}\) 表示如果要保留 \(x\) 至少需要的深度。
    点击查看代码
    int ch[500010][2],fa[500010],f[500010],ans[500010],h[500010],dep[500010],lim[500010],used[500010];
    #define lson(rt) (ch[rt][0])
    #define rson(rt) (ch[rt][1])
    void dfs(int x)
    {
    	if(x==0)
    	{
    		return;
    	}
    	h[x]=dep[x]=dep[fa[x]]+1;
    	dfs(lson(x));
    	dfs(rson(x));
    	h[x]=max(h[x],max(h[lson(x)],h[rson(x)]));
    }
    void pushup(int x,int &k)
    {
    	used[x]=max(used[x],dep[x]);
    	for(int rt=x;rt!=0;rt=fa[rt])
    	{
    		k-=(ans[rt]==0);//中途往上更新没有选中的点
    		ans[rt]=1;
    		used[fa[rt]]=max(used[fa[rt]],dep[x]);
    		if(lson(fa[rt])==rt&&rson(fa[rt])!=0)
    		{
    			lim[rson(fa[rt])]=max(lim[rson(fa[rt])],used[fa[rt]]-1);//符合 AVL 树高度的限制
    		}
    	}
    }
    bool check(int x,int k)
    {
    	int sum=0;
    	for(int rt=x;rt!=0;rt=fa[rt])
    	{
    		sum+=(ans[rt]==0);
    		if(lson(fa[rt])==rt)
    		{
    			sum+=f[max({used[fa[rt]]-1,dep[x]-1,lim[rson(fa[rt])]})-dep[fa[rt]]];//计算额外需要多少个点
    		}
    	}
    	return sum<=k;
    }
    void solve(int x,int &k)
    {
    	if(x==0)
    	{
    		return;
    	}
    	if(check(x,k)==true)
    	{
    		pushup(x,k);
    	}
    	if(lson(x)!=0&&rson(x)!=0)
    	{
    		if(h[lson(x)]>=lim[x])
    		{
    			lim[lson(x)]=max(lim[lson(x)],lim[x]);//左子树已经够了,直接更新左子树
    			lim[rson(x)]=max(lim[rson(x)],lim[x]-1);
    		}
    		else
    		{
    			lim[lson(x)]=max(lim[lson(x)],lim[x]-1);//左子树不够
    			lim[rson(x)]=max(lim[rson(x)],lim[x]);
    		}
    	}
    	else
    	{
    		if(lson(x))
    		{
    			lim[lson(x)]=max(lim[lson(x)],lim[x]);
    		}
    		if(rson(x))
    		{
    			lim[rson(x)]=max(lim[rson(x)],lim[x]);
    		}
    	}
    	solve(lson(x),k);
    	solve(rson(x),k);
    }
    int main()
    {
    	freopen("avl.in","r",stdin);
    	freopen("avl.out","w",stdout);
    	int n,k,rt=0,i;
    	cin>>n>>k;
    	f[1]=1;
    	for(i=2;i<=30;i++)
    	{
    		f[i]=f[i-1]+f[i-2]+1;
    	}
    	for(i=1;i<=n;i++)
    	{
    		cin>>fa[i];
    		if(fa[i]==-1)
    		{
    			fa[i]=0;
    			rt=i;
    		}
    		else
    		{
    			ch[fa[i]][fa[i]<i]=i;
    		}
    	}
    	dfs(rt);
    	solve(rt,k);
    	for(i=1;i<=n;i++)
    	{
    		cout<<ans[i];
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T3\) T2211. 暴雨 \(20pts\)

  • 部分分

    • \(20pts\) :爆搜。
    点击查看代码
    const ll p=1000000007;
    ll h[25010],tmp[25010],lmax[25010],rmax[25010],ans=0;
    void dfs(ll pos,ll n,ll k)
    {
    	if(pos==n+1)
    	{
    		if(k==0)
    		{
    			ll sum=0;
    			lmax[0]=rmax[n+1]=0;
    			for(ll i=1;i<=n;i++)
    			{
    				lmax[i]=max(lmax[i-1],tmp[i]);
    			}
    			for(ll i=n;i>=1;i--)
    			{
    				rmax[i]=max(rmax[i+1],tmp[i]);
    			}
    			for(ll i=1;i<=n;i++)
    			{
    				sum^=((min(lmax[i],rmax[i])-tmp[i])&1);
    			}
    			if(sum==0)
    			{
    				ans=(ans+1)%p;
    			}
    		}		
    	}
    	else
    	{
    		tmp[pos]=h[pos];
    		dfs(pos+1,n,k);
    		if(k>=1)
    		{
    			tmp[pos]=0;
    			dfs(pos+1,n,k-1);
    		}
    	}
    }
    int main()
    {
    	freopen("rain.in","r",stdin);
    	freopen("rain.out","w",stdout);
    	ll n,k,i;
    	cin>>n>>k;
    	for(i=1;i<=n;i++)
    	{
    		cin>>h[i];
    	}
    	dfs(1,n,k);
    	cout<<ans<<endl;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T4\) T2197. 置换 \(0pts\)

\(T5\) T2198. 传统题 \(10pts\)

  • 部分分

    • \(10pts\) :爆搜。
    点击查看代码
    ll a[300010],ans=0;
    void dfs(ll pos,ll n,ll m,ll p)
    {
    	if(pos==n+1)
    	{
    		ll maxx=0,len=0;
    		for(ll i=1;i<=n;i++)
    		{
    			len=(a[i]==a[i-1])?len+1:1;
    			maxx=max(maxx,len);
    		}
    		ans=(ans+maxx)%p;
    	}
    	else
    	{
    		for(ll i=1;i<=m;i++)
    		{
    			a[pos]=i;
    			dfs(pos+1,n,m,p);
    		}
    	}
    }
    int main()
    {
    	freopen("sequence.in","r",stdin);
    	freopen("sequence.out","w",stdout);
    	ll n,m,p;
    	cin>>n>>m>>p;
    	dfs(1,n,m,p);
    	cout<<ans<<endl;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
    

总结

  • 貌似题目出难了,基本上是全程罚坐。
  • \(T2\) 第一遍读题时没注意到仍要求是一棵平衡树。

后记

  • 因 \(T4\) 之前被出在了 初三奥赛模拟测试3 里,所以 \(huge\) 把 \(T5\) 放了进来,让我们最后再写“我们做过的且码量较大的” \(T4\) 。

标签:11,rt,int,lim,ll,fa,csp,模拟,rson
From: https://www.cnblogs.com/The-Shadow-Dragon/p/18464706

相关文章

  • CSP模拟赛 #37
    A题意:给定\(n,a_{1\simn},b_{1\simn}\),两个点\(i,j\)之间有连边当且仅当\(a_i-a_j\lei-j\leb_i-b_j\)或\(a_j-a_i\lej-i\leb_j-b_i\),求图中连通块数量。\(1\len\le10^6\)考虑条件\(a_i-a_j\lei-j\leb_i-b_j\)相当于\(a_i-i\lea_j......
  • csp-s模拟11
    E题面最暴力的做法,枚举连续段长度\(i\),然后暴力搜索,复杂度\(O(n^3)\)点击查看代码#include<bits/stdc++.h>#definespeed()ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);#definelllonglong#definepbpush_back#defineullunsignedlonglong#define......
  • Windows11下安装wsl报错:无法解析服务器的名称或地址
    问题描述之前在自己的笔记本电脑(Windows10)上下载安装WSL很顺利,具体教程见前面的文章,但是在新电脑(Windows11)上下载就报错:无法解析服务器的名称或地址,按照网上说的两个解决方案:修改 DNS 为手动114.114.114.114;查询 raw.githubusercontent.com 这个域名对应的能ping通的ip,......
  • Windows11右键菜单一取消/恢复Win11二级菜单
    Win11更新后,右键菜单很多功能使用时需要点击“显示更多选型”才能获取完整功能,以下有几种方法可以自动展开Win11的二级菜单,恢复到Win10模式。​方法一:reg1.按住win+R打开运行窗口​2.输入【regedit】进入注册表编辑器定位到以下位置:计算机\HKEY_CURRENT_USER\Software\Cl......
  • 1014 CW 模拟赛 B.旅行
    题面现在的题似乎都找不到原题了挂个pdf题面下载算法容易想到链和菊花图的做法,需要注意的是计算深度只能用\(\rm{dfs}\)来跑,不能保证链的顺序与输入顺序相同对于\(n,m\leq10^3\),观察暴力做法暴力容易发现对于每一个点,都要由起点\(1\)开始,先到达一条链......
  • 实战!oracle 11g一键安装脚本分享
    分享一个常用的数据库一键安装脚本,大家可以从我的网盘进行下载链接:https://pan.baidu.com/s/1iV-0zeXrwhJxJcm9qA_P_g提取码:apbc脚本内容:#!/bin/bash#一键安装oracle数据库#修改主机名hostnamectlset-hostnamemyoracle#添加主机名与IP对应记录public_ip=$(hostn......
  • 逍遥安卓模拟器命令行合集(memuc命令)
    逍遥安卓模拟器命令行合集(memuc命令)用cmd自行测试模拟器配合工具:memuc是v6.0.0版本推出的命令行工具,它封装了MEmuConsole、MEmu、MEmuManage的接口,支持多开管理、修改配置、android通信、adb命令等功能。memuc支持多个模拟器的管理,所以某些命令需要传入模拟器序号或者模......
  • YOLOv11改进策略【注意力机制篇】| 2024 PPA 并行补丁感知注意模块,提高小目标关注度
    一、本文介绍本文记录的是利用PPA(并行补丁感知注意模块)改进YOLOv11检测精度,详细说明了优化原因,注意事项等。原论文在红外小目标检测任务中,小目标在多次下采样操作中容易丢失关键信息。PPA模块通过替代编码器和解码器基本组件中的传统卷积操作,更好地保留小目标的重要信息。......
  • <<迷雾>> 第11章 全自动加法计算机(6)--一只开关取数 示例电路
    用一只开关依次将数取出info::操作说明刚启动时,t0=1,t1=t2=0,此时只有IAR`=1.按下开关K不要松开,地址寄存器AR收到一个上升沿信号,保存住当前地址,并提供给存储器(注:第一个地址为0,所以电路中暂看不出什么变化)松开开关K,循环移位计数器RR得到......
  • 2024.10.14 1105版
    起于《海奥华预言》的思考◆地球管理结构和参考持续更新中...... 英文地址:https://github.com/zhuyongzhe/Earth/tags中文地址:https://www.cnblogs.com/zhuyongzhe85作者:朱永哲 ---------------------------------------------------------------------------------......