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 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;
}