2021.07.06【NOIP提高B组】模拟 总结

本文总结了2021年NOIP提高B组模拟赛的四道算法题解。第一题利用并查集解决区间问题;第二题采用动态规划结合单调队列或线段树优化;第三题通过最小生成树找到最优解;第四题通过贪心策略求解。文章详细介绍了每道题的思路和代码实现。

2021.07.06【NOIP提高B组】模拟 总结

第一题:发现答案是一段区间,每次暴力加边,用并查集判断一下。

第二题:显然是动态规划,然后单调队列或线段树优化。

第三题:考虑把组合起来的数算出来,如果这个数为000,计算一下最小代价ccc,就是一个最小生成树。接着我们设fif_ifi表示选了状态为iii的答案。转移就是fi∣j=fi+cjf_{i|j}=f_{i}+c_jfij=fi+cj

第四题:考虑把车站算成一个点n+1n+1n+1,然后能走的边一定是在这个图的最大生成树上。贪心选择做这个题,不要管买不能丢钱的限制,每次选完所有的钱,然后贪心做一下,看一看树上的两点上最小的权值是多少,去一下min⁡\minmin

#include<bits/stdc++.h>
using namespace std;
long long n,m,q,ord[100005],lim[100005];
struct edge{
	long long x,y,z;
}e[200005];
long long fa[100005],tra[100005];
bool cmp(edge e1,edge e2){
	return e1.z>e2.z;
}
const long long inf=1000000000000000000;
long long cnt=0,la[100005],to[400005],we[400005],ne[400005],f[100005][17],g[100005][17],dep[100005];
void add(long long x,long long y,long long z){
	++cnt;
	to[cnt]=y;
	we[cnt]=z;
	ne[cnt]=la[x];
	la[x]=cnt;
}
long long find(long long x){
	if (x==fa[x]) return x;
	else return fa[x]=find(fa[x]);
}
void dfs(long long x,long long y,long long w){
	f[x][0]=y;
	g[x][0]=w;
	for (long long i=1;i<=16;i++){
		f[x][i]=f[f[x][i-1]][i-1];
		g[x][i]=min(g[x][i-1],g[f[x][i-1]][i-1]);
	}
	dep[x]=dep[y]+1;
	for (long long i=la[x];i;i=ne[i]){
		long long z=to[i];
		if (z!=y)
			dfs(z,x,we[i]);
	}
}
void query(long long &ans1,long long &ans2,long long x,long long y){
	if (x==y){
		ans1=inf;
		ans2=0;
		return;
	}
	if (dep[x]<dep[y]) swap(x,y);
	ans1=ans2=inf;
	long long k=dep[x]-dep[y],s=0;
	while (k){
		if (k&1) ans1=min(ans1,g[x][s]),x=f[x][s];
		s++;
		k>>=1;
	}
	if (x==y){
		ans2=x;
		return;
	}
	for (long long i=16;i>=0;i--){
		if (f[x][i]!=f[y][i]){
			ans1=min(ans1,min(g[x][i],g[y][i]));
			x=f[x][i];
			y=f[y][i];
		}
	}
	ans1=min(ans1,min(g[x][0],g[y][0]));
	ans2=f[x][0];
	return;
}
int main(){
	freopen("motorcycle.in","r",stdin);
	freopen("motorcycle.out","w",stdout);
	scanf("%lld%lld%lld",&n,&m,&q);
	for (long long i=1;i<=n;i++) scanf("%lld",&ord[i]);
	for (long long i=1;i<=n;i++) scanf("%lld",&lim[i]);
	for (long long i=1;i<=m;i++) scanf("%lld%lld%lld",&e[i].x,&e[i].y,&e[i].z);
	while (q--){
		long long x;
		scanf("%lld",&x);
		tra[x]=1;
	}
	for (long long i=1;i<=m;i++){
		if (tra[e[i].x]) e[i].x=n+1;
		if (tra[e[i].y]) e[i].y=n+1;
		if (e[i].x==e[i].y) e[i].z=0;
	}
	sort(e+1,e+m+1,cmp);
	int tot=0;
	for (long long i=1;i<=n+1;i++) fa[i]=i;
	for (long long i=1;i<=m;i++){
		long long x=find(e[i].x);
		long long y=find(e[i].y);
		if (x==y) continue;
		else{
			add(e[i].x,e[i].y,e[i].z);
			add(e[i].y,e[i].x,e[i].z);
			fa[x]=y;
		}
	}
	long long root=0;
	for (long long i=1;i<=n+1;i++)
		if (la[i])
			root=i;
	dfs(root,0,inf);
	long long now=ord[1],nsum=lim[ord[1]];
	if (nsum<=0){
		printf("%lld\n",0);
		nsum=max(nsum,(long long)0);
	}
	for (long long i=2;i<=n;i++){
		long long x=(tra[ord[i-1]]?(n+1):ord[i-1]);
		long long y=(tra[ord[i]]?(n+1):ord[i]);
		long long lca,dis;
		query(dis,lca,x,y);
		nsum=min(nsum,dis);
		if (lim[ord[i]]<0){
			printf("%lld\n",min(nsum,-lim[ord[i]]));
		}
		nsum+=lim[ord[i]];
		nsum=max(nsum,(long long)0);
	}
}
Java是一种具备卓越性能与广泛平台适应性的高级程序设计语言,最初由Sun Microsystems(现属Oracle公司)的James Gosling及其团队于1995年正式发布。该语言在设计上追求简洁性、稳定性、可移植性以及并发处理能力,同时具备动态执行特性。其核心特征与显著优点可归纳如下: **平台无关性**:遵循“一次编写,随处运行”的理念,Java编写的程序能够在多种操作系统与硬件环境中执行,无需针对不同平台进行修改。这一特性主要依赖于Java虚拟机(JVM)的实现,JVM作为程序与底层系统之间的中间层,负责解释并执行编译后的字节码。 **面向对象范式**:Java全面贯彻面向对象的设计原则,提供对封装、继承、多态等机制的完整支持。这种设计方式有助于构建结构清晰、模块独立的代码,提升软件的可维护性与扩展性。 **并发编程支持**:语言层面集成了多线程处理能力,允许开发者构建能够同时执行多项任务的应用程序。这一特性尤其适用于需要高并发处理的场景,例如服务器端软件、网络服务及大规模分布式系统。 **自动内存管理**:通过内置的垃圾回收机制,Java运行时环境能够自动识别并释放不再使用的对象所占用的内存空间。这不仅降低了开发者在内存管理方面的工作负担,也有效减少了因手动管理内存可能引发的内存泄漏问题。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值