题目: (洛谷)P9587 「MXOI Round 2」排名

排名结构体练习(c/c++)


可知:


要求:


分析:

容易发现 a 的顺序对答案无影响,(虽然最后是按照a的输入顺序打印,但我们可以用结构体将这个一顺序存储起来,最后按照结构体存储的顺序打印出来),所以我们先将 a 从大到小排序,i的顺序的

上图为:f(p)<=k<=g(p);          注:  a_{p}=a_{p+1}=a_{p+2}=a_{q}当然 p<=q ;所以f(i)<=g(i)


 

因为F(i);和G(i);都是表示个数;所以将a[]从大到小排列,然后F,G都可以用 a [ ] 排序后的序号来表示;也方便与数字k做比较;

F(i) = i ;(排序后的序号) , (虽然不包括ai但等于大于 a_{i} 的数+1,所以还是F(i)=i) 

所以 F(k) = k (临界值)                                                                        ---F(i) 表示:比ai大的个数+1

G(i) = q ;(G(i)=F(i)+与 a_{i} 相等的个数)

所以可以知道  G(i)>=F(i)一定存在

所以题目要求就是   i <= k <= q;_{}^{}

方法:

思想:

(i从0 到 n 依次+1)

  1. i<k;    就是F(i)<k,所以还需要G(i)>k;,如果G(i)>=k;不用操作;如果G(i)<k需要将G(i)变成>=k;最少的操作一定是变成相等的,所以任务就是变成G(i)=k,
  2. i=k, 就是F(i)=k,因为 G(i)>=F(i), 所以F(i)=k<=G(i);  不需要操作;now=0;
  3. i>k,    就是F(i)>k ;需要将F(i)变成<=k;z最少的操作一定是变成相等的,所以任务就是变成F(i)=k,

具体步骤:

1.要使G(i)>=F(i);就是将  第 i个~~~第k个;全变成与ai相等的数;

方法:①(a_{i}-a_{i+1})+(a_{i}-a_{i+2})```````````(a_{i}-a_{k}

方法:② 将ai~ak全看成ai(和是

a_{i}*(k-i+1))减去自己原来的值(a_{i+1},a_{i+2},a_{i+3}

2.不需要操作;now = 0;

3.F(i)增加到 k ;也就是将 a_{i} 长大到a_{k}就好了;因为a_{k}对应的F(k)=k;注:自己变大了比自己大的就少了;(F(i)是比a_{i} 大的个数+1;a_{i}变大的话,比a_{i}大的就少了,F(i)就变小了)

所以需要操作a_{k}-a_{i}次;

代码:

#include<iostream>
#include<algorithm>
#include<cmath>
#define int long long
using namespace std;
int c,n,k,s[500010],ans[500010];
struct node{int x,id;}a[500010];
bool cmp(const node &x,const node &y){
    return x.x>y.x;
}
signed main()
{
    cin>>c>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].x;
        a[i].id=i;
    }
    sort(a+1,a+n+1,cmp);
    //for(int i=1;i<=n;i++)cout<<a[i].x<<endl;
    for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i].x; //前i项和 
    for(int i=1;i<=n;i++)
        if(a[i].x!=a[i-1].x)
        {			//f等于比ai大的个数+1 
            int now;
            if(i>=k)now=a[k].x-a[i].x;   //需要做的是将F减小;使F=K; 
            // 将 a[i].x+到= a[k].x,这样比他大的就k个了 
            else now=a[i].x*(k-i+1)-(s[k]-s[i-1]);//需要做的是将G增大;使G=K; 
            //需要 k-i+1项 (a[i].x~~~a[k].x) 都变成a[i].x +1
            //将 (a[i].x~~~a[k].x)全看成等于 a[i].x然后再减去原来的数 (a[i].x~~~a[k].x)
            //就是 a[i].x*(k-i+1)-(a[i].x~~~a[k].x);
           // 也就是 a[i].x*(k-i+1)-(s[k]-s[i-1]);
			 
            for(int j=i;a[j].x==a[i].x;j++)ans[a[j].id]=now; //相同的一起处理 
        }
    for(int i=1;i<=n;i++)cout<<ans[i]<<endl;
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值