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

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

A

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

写nm贪心活该挂大分

B

首先对于没有 \(0\) 的情况,\(a_i>a_{i+1}\) 且满足 \(i\) 最小肯定要删去 \(i\)

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

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

再者,若 \(a_{i+1}=0\),考虑 \(i+1\) 填的数,对于 \(a_i\)\(a_{i+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

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

该算法是正确的,当且仅当给定点集 \(V_1\)\(G\) 上的虚树点
\(V'_1\)\(V_1\)相同。

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

关于如何维护虚点:可以考虑倒着做,每次删去一个点。如果删去的这个点
有三条及以上的边相连,它就转型成为虚点。如果某次删除后,某个虚点只有
两条边相连,则该虚点消失。答案为 \(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 @ 2022-10-12 14:35  RuntimeErr  阅读(23)  评论(0编辑  收藏  举报