The Parade CodeForces - 1250J(二分)

The Berland Army is preparing for a large military parade. It is already decided that the soldiers participating in it will be divided into kk rows, and all rows will contain the same number of soldiers.

Of course, not every arrangement of soldiers into kk rows is suitable. Heights of all soldiers in the same row should not differ by more than 1. The height of each soldier is an integer between 1 and nn.

For each possible height, you know the number of soldiers having this height. To conduct a parade, you have to choose the soldiers participating in it, and then arrange all of the chosen soldiers into kk rows so that both of the following conditions are met:

  • each row has the same number of soldiers, 
  • no row contains a pair of soldiers such that their heights differ by 2 or more. 

Calculate the maximum number of soldiers who can participate in the parade.

Input

The first line contains one integer tt (1≤t≤10000) — the number of test cases. Then the test cases follow. 

Each test case begins with a line containing two integers nn and kk (1≤n≤30000, 1≤k≤10^12) — the number of different heights of soldiers and the number of rows of soldiers in the parade, respectively.

The second (and final) line of each test case contains nn integers c1, c2, ..., cn (0≤ci≤10^12), where ci is the number of soldiers having height ii in the Berland Army.

It is guaranteed that the sum of nn over all test cases does not exceed 30000.

Output

For each test case, print one integer — the maximum number of soldiers that can participate in the parade.

 

题目大意:有n种身高的人,其中身高i的有a[i]人,这些人要排成k行,且每一行任意两人之间的身高差不能超过2,问最多有多少人可以排到队伍中去。

思路:这题是用二分来做,但是在比赛时一直都没想用二分做,即使在比赛结束后有人告诉我用二分我也不知道咋二分,看来我的二分学的不咋地。

首先我们来看数据范围,显然是非常大的,所以暴力是不行的,这时候我们就可以从我们的算法妙妙屋里掏出二分了,那么怎么二分呢。

我们知道行数是固定的所以我们二分的就是每一行能站多少人。我们可以先用mid当成一排的人数,如果a[i]>mid那么可以凑成一排,之后让a[i]%mid看会剩下多少人,让剩下的人和下一个身高的人加起来是否>mid如果大于同上操作。

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define ll long long
ll a[30005],k;
int n;
bool er(ll mid)
{
    ll ans=0/*看a[i]排完一排之后剩下的人数*/,line=0/*现在有几排*/;
    for(int i=0;i<n;i++)
    {
        if(a[i]+ans<mid)//看当前身高的人数加上上一个身高的人数是否可以凑成一排
            ans=0;
        line+=(a[i]+ans)/mid;//当前有多少排
        ans=(a[i]+ans)%mid;//剩下多少人
        if(line>=k) return true;如果大于或者等于规定的行数就结束
    }
    return false;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(a,0,sizeof(a));
        scanf("%d%lld",&n,&k);
        for(int i=0;i<n;i++)
        {
            scanf("%lld",&a[i]);
        }
        ll l=1,r=1e18,sum=0;
        while(l<=r)
        {
            ll mid=(l+r)/2;
            if(er(mid))
            {
                sum=mid;//如果mid是合适的人数那么记录下来,并让下界升高
                l=mid+1;
            }
            else
            {
                r=mid-1;//不符合条件让上界降低
            }
        }
        printf("%lld\n",sum*k);
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值