20200328省选模拟

思路借鉴来源

T1

类似于赛道修建

这道题一开始把 , ; , ; ,;打错了从正解挂到 12 p t s 12pts 12pts呵呵我真的想拿头调代码
思路:因为是要最大化最小值,于是以 1 1 1为下界 n − 1 n-1 n1为上界二分 k k k值,然后 d f s dfs dfs判断是否合法。
考虑如何 d f s dfs dfs:递归 u u u的所有儿子 v v v v v v会为 u u u带来一条 l e n v + 1 len_v+1 lenv+1长度的边( 1 1 1 u u u v v v之间的边)。开个 v e c t o r vector vector记录当前节点下方所有的子链长度,然后对 v e c t o r vector vector按照长度排序,此时我们有两种方案:
一:直接将 u u u子树上的链两两匹配(贪心思想),对 f a u fa_u fau不造成影响(如果链的长度为奇数就向当前 v e c t o r vector vector里加入一条长度为 0 0 0的链进行匹配)
二:尝试将所有边两两匹配,尝试完成后选出一条无法匹配的边传给 u u u的父节点 f a u fa_u fau处理(注意这条边应该在保证其他边都匹配合法的情况下尽可能长显然
u = = 1 u==1 u==1(根节点)时只有方案一可行,当 u   ! = 1 u\ !=1 u !=1时首先考虑方案二(因为要使传给父节点的边尽量长,能保证上面可行,这样更优),方案二不可行再考虑方案一,若两个方案都不可行则无解)。若选择方案二,直接将二分的长度作为要向上传的长度即可。
m u l t i s e t multiset multiset v e c t o r vector vector更优,但我不会告辞

#include <bits/stdc++.h>
#define vi vector<int>
#define pb push_back
using namespace std;
const int N=(int)2e5+50;
vi len[N];
int fir[N],tot,to[N],nxt[N],n,r,l,dp[N],mid;
inline void addedge(int x,int y){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;}
inline int read(){
	int cnt=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)){cnt=(cnt<<3)+(cnt<<1)+(c^48);c=getchar();}
	return cnt*f;
} 
inline bool check(int u,int mid,int val){
	for(int i=0,j=len[u].size()-1;i<j;i++,j--){
		if(i==mid)i++;
		if(j==mid)j--;
		if(len[u][i]+len[u][j]<val)return 0;
	}
	return 1;
}
inline int dfs(int u,int fa,int val){
	len[u].clear();
	for(int i=fir[u];i;i=nxt[i]){
		int v=to[i];
		if(v==fa)continue;
		if(!dfs(v,u,val))return 0;
		len[u].pb(dp[v]+1);
	}
	int sz=len[u].size();
	if((fa&&!(sz&1))||(!fa&&(sz&1)))len[u].pb(0);
	sort(len[u].begin(),len[u].end());
	if(!fa){
		for(int i=0;i<(sz>>1);i++)if(len[u][i]+len[u][sz-i-1]<val)return 0;
	}
	else{
		if(!check(u,0,val))return 0;
		int l=0,r=sz-1;
		while(l<r){
			int mid=(l+r+1)>>1;
			if(check(u,mid,val))l=mid;
			else r=mid-1;
		}
		dp[u]=len[u][l];
	}
	return 1;
}
int main(){
	n=read();
	for(int i=1;i<n;++i){int x=read(),y=read();addedge(x,y);addedge(y,x);}
	l=1;r=n-1;
	while(l<r){
		mid=(l+r+1)>>1;memset(dp,0,sizeof(dp));
		if(dfs(1,0,mid))l=mid;
		else r=mid-1;
	}
	memset(dp,0,sizeof(dp));
	if(dfs(1,0,l))printf("%d",l);
	else printf("0");
	return 0;
}

T2

咕咕咕

T3

咕咕咕

我感觉我即将从省选滚回联赛/kk

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值