AtCoder Beginner Contest 352

AtCoder Beginner Contest 352

A - AtCoder Line

N,X,Y,Z 判断是否 min(X,Y)Zmax(X,Y)

模拟。

点击查看代码
#include<bits/stdc++.h>
#define int long long

using namespace std;
int n,x,y,z;
signed main(){
	cin>>n>>x>>y>>z; if(x>y) swap(x,y);
	if(x<=z&&z<=y) cout<<"Yes";
	else cout<<"No";
	return 0;
}

B - Typing

S,T,而 ST 的字典序最小子序列,求 ST 中的位置。

模拟。

点击查看代码
#include<bits/stdc++.h>
#define int long long

using namespace std;
char s[200003],t[200003];
signed main(){
	cin>>s>>t;
	int pos=0;
	for(int i=0;t[i];i++){
		if(t[i]==s[pos]) cout<<i+1<<' ',pos++;
	}
	return 0;
}

C - Standing On The Shoulders

N 个巨人,他们的名字分别是 1N 。当巨人 i 站在地上时,他们的肩高是 Ai ,头高是 Bi

你可以选择 (1,2,,N)(P1,P2,,PN) 排列组合,并根据以下规则堆叠 N 个巨人:

  • 首先,将 P1 巨人放在地上。巨人 P1 的肩膀距离地面的高度为 AP1 ,头部距离地面的高度为 BP1
  • 为了 i=1,2,,N1 的顺序,要把巨人 Pi+1 放在巨人 Pi 的肩膀上。如果巨人 Pi 的肩膀距离地面的高度是 t ,那么巨人 Pi+1 的肩膀距离地面的高度就是 t+APi+1 ,他们的头距离地面的高度就是 t+BPi+1

求最上面的巨人 PN 的头部距离地面的最大可能高度。

贪心,显然肩膀的高度是堆叠的,而头的高度只能算一个,所以把所有肩膀加上以后再找到头到肩膀高度差最大的那个就行。

点击查看代码
#include<bits/stdc++.h>
#define int long long

using namespace std;
int n,a,b,mx,ans;
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a>>b;
		ans+=a,mx=max(b-a,mx);
	}
	cout<<ans+mx;
	return 0;
}

D - Permutation Subsequence

给你一个排列 P,求一个长度为 k 的子序列,使得该子序列的数字是连续的,且子序列头尾位置差最小。

类似滑动窗口,因为要求数字连续,所以我们可以用 set 维护每连续 k 个数的位置最大最小值,然后向右滑动更新答案即可。

点击查看代码
#include<bits/stdc++.h>
#define int long long

using namespace std;
int n,k;
int pos[200003],a[200003];
set<int>s;
signed main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i],pos[a[i]]=i;
	}
	for(int i=1;i<=k;i++) s.insert(pos[i]);
	auto it=s.end(); it--;
	int ans=(*it)-(*(s.begin()));
	for(int i=k+1;i<=n;i++){
		s.erase(pos[i-k]);
		s.insert(pos[i]);
		it=s.end(); it--;
		ans=min(ans,(*it)-(*(s.begin())));
	}
	cout<<ans;
	return 0;
}

E - Clique Connect

给你一个加权无向图 G ,有 N 个顶点,编号为 1N 。最初, G 没有边。

您需要执行 M 次操作来为 G 添加边。 (1iM)i -th 操作如下:

  • 给你一个由 Ki 个顶点组成的顶点子集 Si={Ai,1,Ai,2,,Ai,Ki} 。对于每一对 u,v ,即 u,vSiu<v ,在顶点 uv 之间添加一条边,权重为 Ci

完成所有 M 操作后,确定 G 是否相连。如果是,求 G 最小生成树中各条边的总重。

将问题分成两部分,一是判断连通,二是求 MST。

一很好弄,因为所给的每个每个集合之间的块是连通的,直接用并查集处理。

二的话,每个集合里的边是平方级别的,而我们只需要保证连通即可求 MST,所以每个集合里的点只需要保留 Ki1 条边即可。最后再对图用 Kruskal 求 MST 即可,时间复杂度 O(KlogK)

点击查看代码
#include<bits/stdc++.h>
#define int long long

using namespace std;
int n,m;
int fa[400003],k[400003],c[400003];
vector<int>a[400003];
void init(){for(int i=1;i<=n;i++)fa[i]=i;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void merge(int x,int y){fa[find(x)]=find(y);}
bool query(int x,int y){return find(x)==find(y);}
int ffa[400003];
void finit(){for(int i=1;i<=n;i++)ffa[i]=i;}
int ffind(int x){return ffa[x]==x?x:ffa[x]=ffind(ffa[x]);}
void fmerge(int x,int y){ffa[ffind(x)]=ffind(y);}
bool fquery(int x,int y){return ffind(x)==ffind(y);}
struct edge{
	int u,v,w,id;
	bool operator<(const edge &o)const{return w<o.w;}
}e[800003];int cnt;
signed main(){
	cin>>n>>m; init(); finit();
	for(int i=1;i<=m;i++){
		cin>>k[i]>>c[i];
		for(int j=1,A;j<=k[i];j++){
			cin>>A;
			a[i].push_back(A);
		}
		for(int j=1;j<k[i];j++){
			merge(a[i][j-1],a[i][j]);
			e[++cnt]={a[i][j-1],a[i][j],c[i],cnt};
			e[++cnt]={a[i][j],a[i][j-1],c[i],cnt};
		}
	}
	for(int i=2;i<=n;i++){
		if(!query(i,i-1)){
			cout<<"-1\n";
			return 0;
		}
	}
	int ans=0;
	sort(e+1,e+cnt+1);
	for(int i=1;i<=cnt;i++){
		if(!fquery(e[i].u,e[i].v)){
			fmerge(e[i].u,e[i].v);
			ans+=e[i].w;
		}
	}
	cout<<ans;
	return 0;
}

posted @   view3937  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Title
点击右上角即可分享
微信分享提示