• 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;
    } 
    
  • 相关阅读:
    UITextField的总结
    【实战】登录界面
    点分治学习
    2020/3/1
    2020/2/29
    2020/2/28
    2020/2/27
    2020/2/27
    最小树形图
    Ch’s gift HDU6162
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/13291484.html
Copyright © 2020-2023  润新知