10/12:牛客 tg 第不知道多少场

模拟赛次次垫底,是不是该尽早退役?

A

显然排序后选相邻两个来组合最优,设 fi,j 表示前 i 个元素组 j 队的最小值。

写nm贪心活该挂大分

B

首先对于没有 0 的情况,ai>ai+1 且满足 i 最小肯定要删去 i

再讨论存在 0 的情况,可以用 set 先维护准备填的数(也没必要吧)。

ai=0 则考虑当前填的数 x 和后面最小的数 aj(0),若 x>aj 则显然把 aj 删了填给 i 优。

再者,若 ai+1=0,考虑 i+1 填的数,对于 aiai+1 根据没有 0 的情况判断就行了。

int n,a[N],minn[N];
set<int>st;

void solve(){
	scanf("%d",&n);
	st.clear(); 
	for(int i=1;i<=n;++i)st.insert(i);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i]);
		if(a[i])st.erase(a[i]);
	}minn[n+1]=a[n+1]=n+1;
	for(int i=n;i;--i){
		if(a[i]&&a[i]<a[minn[i+1]])minn[i]=i;
		else minn[i]=minn[i+1];
	}
	for(int i=1;i<=n;++i){
		if(i==n){a[i]=-1;break;}
		if(a[i]&&a[i+1]&&a[i]>a[i+1]){a[i]=-1;break;}
		if(!a[i]){
			int qwq=*st.begin();
			if(a[minn[i]]<qwq){a[minn[i]]=-1;break;}
		}else if(!a[i+1]){
			int qwq=*st.begin();
			if(a[i]>qwq){a[i]=-1;break;}
		}
		if(!a[i])st.erase(st.begin());
	}
	st.clear();
	for(int i=1;i<=n;++i)st.insert(i);
	for(int i=1;i<=n;++i){
		if(!a[i]||a[i]==-1)continue;
		st.erase(a[i]);
	}
	for(int i=1;i<=n;++i){
		if(a[i]==-1)continue;
		if(a[i])printf("%d ",a[i]);
		else printf("%d ",*st.begin()),st.erase(st.begin());
	}printf("\n");
}

C

点集在树上的斯坦纳树即为其虚树。

该算法是正确的,当且仅当给定点集 V1G 上的虚树点
V1V1相同。

因为如果有其他的虚点的话则必然有边多算了一次。

关于如何维护虚点:可以考虑倒着做,每次删去一个点。如果删去的这个点
有三条及以上的边相连,它就转型成为虚点。如果某次删除后,某个虚点只有
两条边相连,则该虚点消失。答案为 1 当且仅当不存在虚点时。

对于边权存在 0 的情况,只需要将所有由 0 边连结的连通块视为一个点,一
个连通块被选中当且仅当其中至少有一个点被选中,然后应用上述做法即可。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<set>
#include<algorithm>
using namespace std;

const int N=3e5+10;

int n,p[N],cnt[N];
int sum=0,ans[N];
set<int>e[N];//学到了用set维护边,方便删除 
struct node{int u,v,w;}edge[N];
#define add(x,y) e[x].insert(y)
#define del(x,y) e[x].erase(y)

int fa[N];
int fnd(int x){return x!=fa[x]?fa[x]=fnd(fa[x]):x;}

void Del(int x){
	if(e[x].size()>2||cnt[x]>0)return;
	--sum;
	int tmp[3],cnt=0;
	for(int v:e[x])tmp[++cnt]=v;
	e[x].clear();
	for(int i=1;i<=cnt;++i){
		for(int j=1;j<=cnt;++j){
			if(i==j)continue;
			add(tmp[i],tmp[j]);
		}
		del(tmp[i],x);
	}
	for(int i=1;i<=cnt;++i)Del(tmp[i]);
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)fa[i]=i;
	for(int i=1;i<n;++i){
		scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
		if(!edge[i].w)fa[fnd(edge[i].u)]=fnd(edge[i].v);
	}
	for(int i=1;i<n;++i)if(edge[i].w)add(fnd(edge[i].u),fnd(edge[i].v)),add(fnd(edge[i].v),fnd(edge[i].u));
	for(int i=1;i<=n;++i)scanf("%d",&p[i]),++cnt[fnd(p[i])];
	for(int i=n;i;--i){
		ans[i]=!sum;
		if(!--cnt[fnd(p[i])])++sum,Del(fnd(p[i]));
	}
	for(int i=1;i<=n;++i)printf("%d",ans[i]);
	return 0;
}

D

心累,不想补了

posted @   RuntimeErr  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示