蓝桥杯第十三届JavaB组省赛真题-最少刷题数

题目

小蓝老师教的编程课有 N 名学生,编号依次是 1 . . . N。第 i 号学生这学期刷题的数量是 Ai。

对于每一名学生,请你计算他至少还要再刷多少道题,才能使得全班刷题比他多的学生数不超过刷题比他少的学生数。

输入格式

第一行包含一个正整数 N。

第二行包含 N 个整数:A1, A2, A3, . . . , AN.

5

12 10 15 20 6

 输出格式

输出 N 个整数,依次表示第 1 . . . N 号学生分别至少还要再刷多少道题。

0 3 0 0 7

题解 

可以用暴力,但是在寻找最少刷题数时会超时,

所以可以利用前缀和求出每个刷题数阶段的人数,

当不满足 刷题数多于当前学生刷题数的人数 不超过 刷题数少于当前学生刷题数的人数

(注意临界点,当当前学生刷题数为0时需特殊处理)

再利用二分法在当前学生刷题数与最大刷题数之间寻找最少刷题数

import java.util.*;
public class LessTopicCount {

        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);

            int n = scanner.nextInt();//人数
            int m = 100000;//最大刷题数
            int [] array = new int[n];//每个人刷题数
            int [] sum = new int[100010];//每个刷题数阶段的人数

            for( int i=0; i<n; i++)
            {
                array[i] = scanner.nextInt();
                //记录每种刷题数出现的次数,即人数
                sum[ array[i] ]++;
            }

            for( int i=1; i<=m; i++)
            {
                //前缀和
                //记录每个阶段(刷0-i题)刷题数的总人数
                sum[i]+=sum[i-1];
            }
            

            for( int i=0; i<n; i++)
            {
                //枚举每个学生的刷题数是否满足
                int l = array[i]; //二分查找左值
                int r = m; //二分查找右值

                if( sum[m]-sum[l] <= sum[Math.max(0, l-1)]) {
                    //注意边界:最少不能少于0道刷题数

                    //刷题比他多的人数小于等于刷题比他少的
                    //那么他就不需要再刷题,直接输出0即可
                    System.out.print(0+" ");
                    continue;
                }
                //二分查找
                while( l<r )//终止条件:刷题数多于他的人数 等于 或 小于 (最接近)刷题数比他少的人数(找最中间的那个刷题数)
                {
                    int mid = l+r>>1;

                    int more = sum[m] - sum[mid];//刷题数大于他的人数
                    int less = sum[mid-1] -1;//刷题数小于他的人数,减1是因为自己不能算

                    //没有提前终止的条件,因为可能有多个人的刷题数相同

                    if( more>less )
                    {
                        //说明刷题数大于他的人数 多了,所以刷题数要增加
                        l = mid+1;
                    }
                    else
                    {
                        //说明刷题数大于他的人数 少了,所以刷题数要减少
                        r = mid;
                    }
                }

                System.out.print((l - array[i]) + " ");

            }
        }

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值