ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

DRŽAVA

2022-07-19 16:00:49  阅读:184  来源: 互联网

标签:int s2 wh inline 排序 DR AVA getchar


link

总感觉COCI的题面读不懂。题意是说给定一些平面内的点,点有点权,两个点连边的边权是两个点的集合距离。请求出一棵生成树,满足树内存在点权和模K为0的子集,最小化最大边的边权。

有一个很巧妙的结论,随意选出K个点一定能找出子集符合条件。于是得出结论树内结点不会超过K个,所以每个点只有最多K条边。于是考虑把每个点的前K小边找出来,从小到大排序,然后暴力加边并更新,一直更新到根有0的方案即可。

考虑为什么单纯按照 \(x\) 坐标排序后取一个点前后的某些点作为最近点会出现错误,显然原因是假如两个点横向靠的很近但纵向距离很远,那么两个点的实际距离是很远的,单纯按照 \(y\) 坐标排序也会出现相似的情况。如果我没理解错的话,第一篇题解的方法是砍去太远的点并且把所有点旋转一个角度,就像某题中的最高赞题解一样。蒟蒻有另一种奇怪的方法,是对横坐标和纵坐标先排两次序,每个点的权值记录为两次排序的位次之和,然后用新的权值再排一次序。可以被卡掉,但我并不认为出题人会可以去卡这种写法(谁能想得到呢对吧)。然后用状压和并查集维护即可。

#include<bits/stdc++.h>
//#define feyn
#define int long long 
const int N=50010;
using namespace std;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
inline int max(int s1,int s2){
	return s1<s2?s2:s1;
}
inline int min(int s1,int s2){
	return s1<s2?s1:s2;
}

int m,n,c[N],data[N];
struct node{int id,x,y;}a[N];
inline bool cmp1(node s1,node s2){return s1.x<s2.x;}
inline bool cmp2(node s1,node s2){return s1.y<s2.y;}
inline bool cmp3(node s1,node s2){return data[s1.id]<data[s2.id];}

inline int pp(int wh){return wh*wh;}
inline int dis(node s1,node s2){return pp(s1.x-s2.x)+pp(s1.y-s2.y);}
struct edge{
	int a,b,val;
}e[N*40];
inline bool cmpe(edge s1,edge s2){
	return s1.val<s2.val;
}
int cnt;

int f[N],p[N];
inline int find(int wh){
	return f[wh]==wh?wh:f[wh]=find(f[wh]);
}
inline void print(int wh){
	for(int i=0;i<n;i++)printf("%d ",(wh&(1<<i))>0);printf("\n");
}
inline int work(int s1,int s2){
	//printf("merging\n");print(s1);print(s2);
	int an=0;
	for(int i=0;i<n;i++){
		if((s1&(1<<i))==0)continue;
		for(int j=0;j<n;j++){
			if((s2&(1<<j))==0)continue;
			an=an|(1<<(i+j)%n);
		}
	}
	return an|s1|s2;
}
inline bool merge(int s1,int s2){
	int f1=find(s1),f2=find(s2);
	if(f1==f2)return false;
	f[f2]=f1;p[f1]=work(p[f1],p[f2]);
	//printf("%lld %lld\n",s1,s2);print(p[f1]);
	return p[f1]&1;
}

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(n);
	for(int i=1;i<=m;i++){
		read(a[i].x);read(a[i].y);read(c[i]);
		c[i]%=n;a[i].id=i;
	}
	sort(a+1,a+m+1,cmp1);
	for(int i=1;i<=m;i++)data[a[i].id]+=i;
	sort(a+1,a+m+1,cmp2);
	for(int i=1;i<=m;i++)data[a[i].id]+=i;
	sort(a+1,a+m+1,cmp3);
	
	for(int i=1;i<=m;i++){
		for(int j=max(1,i-20);j<=min(m,i+20);j++){
			if(i==j)continue;
			e[++cnt]=(edge){a[i].id,a[j].id,dis(a[i],a[j])};
		}
	}
	sort(e+1,e+cnt+1,cmpe);
	//printf("cnt=%lld\n",cnt);
	
	for(int i=1;i<=m;i++)f[i]=i,p[i]=(1<<c[i]);
	for(int i=1;i<=cnt;i++){
		if(merge(e[i].a,e[i].b)){
			printf("%.3f\n",sqrt(e[i].val));
			return 0;
		}
	}
	
	return 0;
}

标签:int,s2,wh,inline,排序,DR,AVA,getchar
来源: https://www.cnblogs.com/dai-se-can-tian/p/16494399.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有