当前位置: 首页 > news >正文

2022杭电多校第六场题解

2022杭电多校第六场

在这里插入图片描述

Maex(树形DP)

题意
给定一棵以1为根的有根树,树上的每个点都有一个权重,顶点 i i i的权重是 a i a_i ai a i a_i ai不是给定的,并且 a i a_i ai互不相同。定义 b u = M E X { x ∣ ∃ v ∈ subtree ⁡ ( u ) , x = a v } b_u=M E X\left\{x \mid \exists v \in \operatorname{subtree}(u), x=a_v\right\} bu=MEX{xvsubtree(u),x=av},求 ∑ i = 1 n b i \sum_{i=1}^n b_i i=1nbi的最大值。其中集合 M E X MEX MEX表示集合中最小的未出现的非负的元素。

分析
由于权值各不相同,对于一点 u u u b u b_u bu的最大值是 s i z e ( u ) size(u) size(u),并且同一个父结点的若干个子树只有一棵子树的 M E X MEX MEX值不为0, b u b_u bu不为0的点形成了根向下走的一条路径。考虑用树形DP求最值,状态转移方程为:
f [ u ] = s z [ u ] + m a x ( f [ v ] ) ( v ∈ s u b t r e e ( u ) ) f[u]=sz[u]+max(f[v])(v \in subtree(u)) f[u]=sz[u]+max(f[v])(vsubtree(u))
时间复杂度 O ( n ) O(n) O(n)

AC代码

typedef long long ll;
const int N=5e5+10;
vector<int> v[N];
ll f[N],sz[N];

void dfs(int x,int p)
{
	ll mx=0;
	sz[x]=1;
	for(auto y:v[x])
	{
		if(y==p) continue;
		dfs(y,x);
		sz[x]+=sz[y];
		mx=max(mx,f[y]);
	}
	f[x]=sz[x]+mx;
}

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		for(int i=1;i<=n;i++) f[i]=sz[i]=0;
		for(int i=1;i<=n;i++) v[i].clear();
		for(int i=1;i<n;i++)
		{
			int x,y;
			cin>>x>>y;
			v[x].push_back(y);
			v[y].push_back(x);
		}
		dfs(1,-1);
		cout<<f[1]<<endl;
	}
	return 0;
}

Shinobu loves trip(数论)

题意
P P P( P P P是质数)个国家,下标从0开始编号。当Shinobu在第 i i i个国家时,她下一个要访问的国家是 ( i ∗ a )   m o d   P (i*a) \ mod \ P (ia) mod P,从一个国家到另一个国家需要1天的时间。现在给出 n n n种旅行方案,每个旅行方案包括起始国家 s i s_i si和旅行天数 d i d_i di。有 q q q次询问,对于每个询问输出有多少种旅行方案经过 x i x_i xi

分析
对于给定的 x x x,判断当前方案是否经过 x x x,只需判断是否 ∃   k ( 0 ≤ k ≤ d i ) \exists \ k(0 \leq k \leq d_i)  k(0kdi)使得 ( s i ∗ a k ) % P = x (s_i*a^k) \% P=x (siak)%P=x,其中 a a a是确定的,可以预处理 a a a的幂和 s i s_i si的逆元。由于 P P P是质数,可以计算出 a k a^k ak的值,再判断是否有满足条件的 k k k。时间复杂度 O ( T ∗ ( max ⁡ ( d i ) + n log ⁡ ( P ) + n q ) ) O\left(T *\left(\max \left(d_{i}\right)+n \log (P)+n q\right)\right) O(T(max(di)+nlog(P)+nq))

AC代码

typedef long long ll;
const int N=1010;
int s[N],d[N],inv[N];
int P,a,n,q;

int ksm(int a,int b)
{
	int ans=1%P;
	for(;b;b>>=1)
	{
		if(b&1) ans=(ll)ans*a%P;
		a=(ll)a*a%P;
	}
	return ans;
}

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		cin>>P>>a>>n>>q;
		int mx=0;
		for(int i=1;i<=n;i++) cin>>s[i]>>d[i],mx=max(mx,d[i]);
		for(int i=1;i<=n;i++) if(s[i]) inv[i]=ksm(s[i],P-2);
		unordered_map<int,int> mp;
		mp[1]=0;
		ll y=a;
		for(int i=1;i<=min(mx,P-2);i++)
		{
			if(!mp.count(y)) mp[y]=i;
			y=y*a%P;
		}
		while(q--)
		{
			int x;
			cin>>x;
			int ans=0;
			if(x==0)
			{
				for(int i=1;i<=n;i++) if(s[i]==0) ans++;
			}
			else
			{
				for(int i=1;i<=n;i++)
				{
					if(s[i]==0)
					{
						if(x==0) ans++;
					}
					else
					{
						ll z=(ll)x*inv[i]%P;
						if(mp.count(z)&&mp[z]<=d[i]) ans++;
					}
				}
			}
			cout<<ans<<endl;
		}
	}
	return 0;
}

注意
如果不预处理 s i s_i si的逆元,时间复杂度会多一个 l o g log log,不能通过本题。

Map(计算几何)

题意
Sakuyalove有一张大的世界地图 M M M和一张小的世界地图 m m m,地图是长方形的,并且小地图由大地图压缩而来,小地图放在大地图的内部(包括边界)。Sakuyalove发现总是存在一点 P P P满足这个点在两个地图中指示的位置相同。现在给出两个地图的坐标,求 P P P点的坐标。

在这里插入图片描述
分析
最开始的想法是由两点坐标求直线的一般式,设出 P P P点坐标,再根据点到直线的距离公式 ∣ A x 0 + B y 0 + C ∣ A 2 + B 2 \frac{\vert Ax_0+By_0+C\vert}{\sqrt{A^2+B^2}} A2+B2 Ax0+By0+C联立两个方程求解,但点到直线距离公式带有绝对值,无法直接计算。后来想到用叉积代替点到直线距离方程,通过面积的比值联立方程,赛时使用的这种方法AC,编码较为复杂。在严格鸽的题解中使用了复数进行求解,方法简便并且代码很短,详见https://zhuanlan.zhihu.com/p/549964144。

题解给出了代数和几何两种方法。

在这里插入图片描述

AC代码

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
complex<double> a[5],b[5],r,t,ans,z;

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		for(int i=1;i<=4;i++)
		{
			double x,y;
			scanf("%lf %lf",&x,&y);
			a[i]={x,y};
		}
		for(int i=1;i<=4;i++)
		{
			double x,y;
			scanf("%lf %lf",&x,&y);
			b[i]={x,y};
		}
		t=(b[1]*a[2]-b[2]*a[1])/(a[2]-a[1]);
		r=(b[1]-t)/a[1];
		z={1,0};
		ans=-t/(r-z);
		printf("%.6f %.6f\n",ans.real(),ans.imag());
	}
	return 0;
}

Planar graph(图论 最小生成树)

题意
如果一个无向图存在一种在平面的绘制方法,保证任意两条边除了端点之外没有交点,那么就说这个无向图是平面图,下图所示是一个平面图。

在这里插入图片描述
下图所示是一张非平面图,可以证明无论怎样画这张图,一定存在两条边有非端点的交点。

在这里插入图片描述
对于一张平面图,它有很多区域被边分割,下面这张图有4个区域,其中区域1是无穷大的。

在这里插入图片描述
给定一个含有 n n n个顶点和 m m m条边的平面图,平面图上的每个区域建立一个国家。你是设计师,并且你可以在两个区域的交界处建立隧道,两个城市之间只能通过隧道相互到达。下图所示是一种建立隧道的方式。

在这里插入图片描述
输出所需建设隧道数量的最小值,使得所有城市都连通。如果有多种方案,输出需要建隧道的边的编号字典序最小的方案。给定的图保证是平面图,但可能含有重边、自环,图也可能不连通。

分析
一个自然的想法是将每个区域看做点,如果两个区域相邻就连边,建图之后跑最小生成树,但是这种思路很难实现。换一种思路,建隧道的过程就是在原图上删边的过程,所有区域连通等价于原图中不存在环。在原图上跑最小生成树就可以得到要保留的边,由于题目要求字典序最小,倒序枚举每条边即可。

AC代码

const int N=2e5+10;
int pa[N];
struct node {
	int x,y;
}p[N];

int find(int x)
{
	return pa[x]==x?pa[x]:pa[x]=find(pa[x]);
}

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n,m;
		cin>>n>>m;
		for(int i=1;i<=n;i++) pa[i]=i;
		for(int i=1;i<=m;i++) cin>>p[i].x>>p[i].y;
		vector<int> ans;
		for(int i=m;i>=1;i--)
		{
			int u=find(p[i].x),v=find(p[i].y);
			if(u==v) ans.push_back(i);
			else pa[u]=v;
		}
		reverse(ans.begin(),ans.end());
		cout<<ans.size()<<endl;
		for(auto x:ans) cout<<x<<" ";
		cout<<endl;
	}
	return 0;
}

注意
在这里插入图片描述

Loop(单调栈 优先队列)

题意
给定一个长度为 n n n的数组,下面要进行 k k k次如下操作:

  • 选择一个区间 [ l , r ] [l,r] [l,r]
  • 将区间 [ l , r ] [l,r] [l,r]内的元素循环左移一个位置

k k k 次操作后数组字典序最大的结果。

分析
每次操作实质上是将一个数放到它后面的某个位置,贪心的从前往后找到第一个满足 a i < a i + 1 a_i<a_{i+1} ai<ai+1 a i a_i ai,将 a i a_i ai 放到后面会使答案更优,这样的 a i a_i ai 最多可以选择 k k k 个。先不考虑 a i a_i ai 放的位置,从前到后处理过的序列一定是非递增的,可以用单调栈维护。为了使字典序最大,可以将选择的 k k k 个数放到优先队列中,从前往后处理一遍后,再将剩余元素和优先队列的元素归并,得到最终结果。时间复杂度 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

AC代码

const int N=3e5+10;
int a[N],b[N],stk[N];
int top;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		int n,k;
		cin>>n>>k;
		for(int i=1;i<=n;i++) cin>>a[i];
		priority_queue<int> q;
		top=0;
		for(int i=1;i<=n;i++)
		{
			while(top&&k&&stk[top]<a[i])
			{
				q.push(stk[top]);
				top--;
				k--;
			}
			stk[++top]=a[i];
		}
		for(int i=1,j=1;i<=n;i++)
		{
			if(j>top)
			{
				b[i]=q.top();
				q.pop();
			}
			else if(!q.size())
			{
				b[i]=stk[j++];
			}
			else
			{
				if(q.top()>stk[j])
				{
					b[i]=q.top();
					q.pop();
				}
				else
				{
					b[i]=stk[j++];
				}
			}
		}
		for(int i=1;i<=n;i++)
		{
			if(i>1) cout<<" ";
			cout<<b[i];
		}
		cout<<endl;
	}
	return 0;
}

注意
Don’t have spaces at the end of the line

相关文章:

  • 基于Python的深度优先搜索和广度搜索----解决迷宫最短路径问题
  • 微服务-SpringCloud学习(一)
  • 八股文之设计模式
  • 第6章 初识Spring框架
  • 【明年找到好工作】:面试题打卡第二天
  • 企业Java实战面试题
  • 多次握手登录
  • gdb调试 常用命令
  • 华为云上安装mysql-5.7.38-极其详细的安装教程
  • vue父子组件传值:父传子、子传父
  • 使用花生壳做内网穿透
  • 基于SSM的学生宿舍管理系统
  • 第二章第六节 ST图与迭代优化
  • Kotlin(九)类、属性、构造函数
  • Java 八股文能不背吗?Java 面试都只是背答案吗?
  • [NodeJS] 关于Buffer
  • jdbc就是这么简单
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • SQL 难点解决:记录的引用
  • tensorflow学习笔记3——MNIST应用篇
  • vue2.0项目引入element-ui
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • Vue实战(四)登录/注册页的实现
  • 工作中总结前端开发流程--vue项目
  • 回流、重绘及其优化
  • 基于axios的vue插件,让http请求更简单
  • 新手搭建网站的主要流程
  • 一份游戏开发学习路线
  • 在Mac OS X上安装 Ruby运行环境
  • nb
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • (30)数组元素和与数字和的绝对差
  • (二)构建dubbo分布式平台-平台功能导图
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (六) ES6 新特性 —— 迭代器(iterator)
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (一) storm的集群安装与配置
  • (一)Thymeleaf用法——Thymeleaf简介
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • .gitignore文件—git忽略文件
  • .NET Core MongoDB数据仓储和工作单元模式封装
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .net利用SQLBulkCopy进行数据库之间的大批量数据传递
  • @hook扩展分析
  • @WebService和@WebMethod注解的用法
  • [ C++ ] template 模板进阶 (特化,分离编译)
  • [Android]使用Android打包Unity工程
  • [BJDCTF2020]The mystery of ip
  • [C/C++]数据结构 循环队列
  • [C++]模板与STL简介
  • [CSS]盒子模型
  • [hdu1561] The more, The Better 【树形DP】
  • [IE编程] 如何设置IE8的WebBrowser控件(MSHTML) 的渲染模式
  • [IMX6DL] CPU频率调节模式以及降频方法
  • [jobdu]不用加减乘除做加法