CodeForces 1361D Johnny and James
阿新 • • 發佈:2020-07-13
CodeForces 1361D Johnny and James
https://codeforces.com/contest/1361/problem/D
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 \rfloor\)時,貢獻係數是非負的.所以只有當\(n-mx < k-\lfloor \dfrac k2 \rfloor\) 其中\(mx\)為最大的鏈的長度,時,才會有一條鏈選擇一段字首.也就是說長度最長的鏈之外的節點全部保留,最長鏈上保留最後\(\lfloor \dfrac k2 \rfloor\)個點和最前面的\(k-(n-mx)-\lfloor \dfrac k2 \rfloor\)個點.
否則,由於每次若選擇一條鏈中的節點,那麼一定是選擇這條鏈中最遠的節點,那麼可以對於貢獻維護優先佇列,每次貪心選擇貢獻最大的節點即可.
複雜度\(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---\n"); 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\n",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\n",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\n",j,t); an+=rec[i][j]*(k-t*2-1); } } } printf("%.12lf\n",an); } void sol1() { // debug("1---\n"); 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\n",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; }