jzoj 5562. 简单构造

Description

一次歌唱比赛中,一位歌手刚刚结束表演,评委正在打分。一共有n 位评委,
他们每人可以打1 分或0 分,第i 位评委希望歌手的得分为v[i]。
评委们有特殊的控分技巧,他们会按一个顺序依次评分,第一个评分的评委
会不管三七二十一打0 分。对于接下来的评委,假设前面a 位评委评分总和为
b,评委会认为这位歌手期望得分为b/a*n,如果这个得分低于他所希望的得
分,他会打1 分,否则他会打0 分。
作为最大的黑幕——裁判,你对这一切心知肚明。你希望选手的得分为p
(0<=p<=n),为此你可以调换评委们的评分顺序。你需要输出一个1~n 的排
列,第i 个位置表示第i 个评分的裁判的编号,让选手的得分最接近p。如果
有多种,你只需要输出任意一种。
 

Input

第一行两个整数n、p,表示评委个数和你对歌手的期望得分。
第二行n 个整数v[1],v[2]…v[n],表示每个评委对歌手的期望得分。
保证0<=p,v[1],v[2]…v[n]<=n。

Output

一行一个1~n 的排列,用空格分开。
 

Sample Input

3 3
0 1 2

Sample Output

1 2 3
 Data Constraint
Subtask 1,10pts,1<=n<=10。
Subtask 2,20pts,1<=n<=100。
Subtask 3,30pts,1<=n<=1000。
Subtask 4,10pts,1<=n<=10^5,p=0。
Subtask 5,30pts,1<=n<=10^5。
Sol :

 

那么我们可以发现,假设裁判的期望得分是有序的,那么按编号顺序投票得分最大,按编号顺序倒序投票得分最小,因为如果这两个不是极值,交换一个相邻的顺序/逆序对不会变劣。

然后二分决策。

code:

#include<bits/stdc++.h>
#define LL long long
#define N  204007

using namespace std;
int n,a[N],now,p,pos[N],id[N]; LL seg;
template <class T>
inline void read(T &x){
    static char c;
    for (c=getchar();!isdigit(c);c=getchar());
    for (x=0;isdigit(c);c=getchar())x=x*10+c-48;
}
void write(int x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);}
inline void writeln(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); }
inline void writel(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); }
void sol(int *a,LL otk){
    for (int i=1;i<=n;i++) a[i]=0;
    seg=n;
    while (seg&&otk>=seg-1) {
        seg--; a[n-seg]=seg+1; otk-=seg;
    }
    if (otk) {
      a[n-otk]=seg; 
    } now=0;
    for (int i=1;i<=n;i++) if (!a[i]) a[i]=++now;
}
int ans,w[N],anw;
LL r,top,ST;
int dos(LL otk) {
    if (otk>1ll*n*(n-1)/2) return -111111111;
    sol(a,otk);
    ans=0;
    for (int i=2;i<=n;i++) 
      if (w[a[i]]-1.0*ans/(i-1)*n>1e-7) ans++;
    return ans;
}
void out(LL otk) {
    sol(a,otk);
    for (int i=1;i<=n;i++)  writel(pos[a[i]]); puts("");
//    for (int i=1;i<n;i++)  {if (a[i]!=a[i+1]+1) {cerr<<"sb "<<i<<endl;exit(0);}}//writel(a[i]); puts("");
    cerr<<(dos(otk))<<endl;
}
signed main () {
    freopen("cs.in","r",stdin);
    freopen("cs.out","w",stdout);
    read(n); read(p);
//    out(1);
//    for (int i=0;i<=n*(n-1)/2;i++) 
//     out(i);
    for (int i=1;i<=n;i++) read(w[i]),pos[i]=i;
    sort(pos+1,pos+n+1,[&](int _x,int _y){return w[_x]<w[_y];});
//    for (int i=1;i<=n;i++) id[pos[i]]=i;
    sort(w+1,w+n+1);
    anw=dos(0);
    if (p>=anw) {out(0); return 0;}
//    l=0; r=n*(n-1)/2;
    r=1ll<<50; ST=0;
    while (r) {
        if (dos(ST+r)>p) 
          ST+=r;
        r>>=1; 
    }
    top=dos(ST)-p<p-dos(ST+1)?ST:ST+1;
//    out(top-1);
    out(top);
//    out(top+1);
    return 0; 
}

 

 

  
posted @ 2018-10-30 18:44  泪寒之雪  阅读(219)  评论(0编辑  收藏  举报