CodeForces 1361D Johnny and James

CodeForces 1361D Johnny and James

https://codeforces.com/contest/1361/problem/D

UGgNod.png

Tutorial

https://codeforces.com/blog/entry/78355?f0a28=1

可以把这道题看作这样一个结构,以((0,0))为根的树,且((0,0))的每个子树都是一条链.

考虑一个基地如果保留的话它对答案的贡献.设它所在链上距离比它大的被选择的点数为(t),它到原点的距离为(d),那么贡献为(d((k-t-1)-t)=d(k-2t-1)).

从这个式子中可以看出,贡献系数为正的时候(d)尽量大,否则(d)尽量小,所以每条链上所选择的是一个前缀和一个后缀.

类比重心,发现当(k-2t-1 ge 0)也就是一条链上选择的节点数不超过(lfloor dfrac k2 floor)时,贡献系数是非负的.所以只有当(n-mx < k-lfloor dfrac k2 floor) 其中(mx)为最大的链的长度,时,才会有一条链选择一段前缀.也就是说长度最长的链之外的节点全部保留,最长链上保留最后(lfloor dfrac k2 floor)个点和最前面的(k-(n-mx)-lfloor dfrac k2 floor)个点.

否则,由于每次若选择一条链中的节点,那么一定是选择这条链中最远的节点,那么可以对于贡献维护优先队列,每次贪心选择贡献最大的节点即可.

复杂度(O(n log n))

Code

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
inline char gc() {
	return getchar();
	static char buf[100000],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void rd(T &x) {
	x=0; int f=1,ch=gc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=gc();}
	x*=f;
}
template<class T> inline bool Cmax(T &x,T y) {return x<y?x=y,1:0;}
typedef long long ll;
const int maxn=5e5+50;
int n,k,mx;
int ncnt;
map< pair<int,int>, int> id;
vector<double> rec[maxn];
int gcd(int a,int b) {return b==0?a:gcd(b,a%b);}
struct node {
	int x,y; double d;
	node(int x=0,int y=0,double d=0):x(x),y(y),d(d){}
	void init() {
		d=sqrt((ll)x*x+(ll)y*y);
		if(x==0&&y==0) return;
		int t=abs(gcd(x,y));
		x/=t,y/=t;
	}
	inline bool operator <(const node &other) const {
		return d<other.d;
	}
} a[maxn];
void sol0() {
//	debug("0---
");
	double an=0;
	for(int i=1;i<=ncnt;++i) {
		if(rec[i].size()!=mx) {
			for(int j=0;j<rec[i].size();++j) {
				int t=rec[i].size()-j-1;
//				debug("%d %d
",j,t);
				an+=rec[i][j]*(k-t*2-1);
			}
		}
		else {
			for(int t=0;t<k/2;++t) {
				int j=rec[i].size()-t-1;
//				debug("%d %d
",j,t);
				an+=rec[i][j]*(k-t*2-1);
			}
			int lim=(k+1)/2-(n-mx);
			for(int j=0;j<lim;++j) {
				int t=k/2+lim-j-1;
//				debug("%d %d
",j,t);
				an+=rec[i][j]*(k-t*2-1);
			}
		}
	}
	printf("%.12lf
",an);
}
void sol1() {
//	debug("1---
");
	double an=0;
	priority_queue<node> q;
	q.push(node(0,0,0));
	for(int i=1;i<=ncnt;++i) q.push(node(i,rec[i].size()-1,rec[i].back()*(k-1)));
	for(int i=1;i<=k;++i) {
		int x=q.top().x,y=q.top().y; an+=q.top().d; q.pop(); 
		if(y==0) continue;
		int t=rec[x].size()-y;
		q.push(node(x,y-1,rec[x][y-1]*(k-t*2-1)));
	}
	printf("%.12lf
",an);
}
int main() {
	rd(n),rd(k);
	for(int i=1;i<=n;++i) rd(a[i].x),rd(a[i].y),a[i].init();
	sort(a+1,a+n+1);
	for(int i=2;i<=n;++i) {
		pair<int,int> t=make_pair(a[i].x,a[i].y);
		if(!id[t]) id[t]=++ncnt;
		rec[id[t]].push_back(a[i].d);
	}
	for(int i=1;i<=ncnt;++i) Cmax(mx,(int)rec[i].size());
	if(n-mx<(k+1)/2) sol0();
	else sol1();
	return 0;
} 
原文地址:https://www.cnblogs.com/ljzalc1022/p/13291484.html