C. 刷票
题目描述:
有一个选秀比赛,节目组按照观众的投票情况决定选手的去留。为了给旗下 艺人造势,A 公司收买了一批水军来刷票。已知现在有 n 名选手同台竞争,依次 编号 1..n,A 公司的艺人编号为 1。根据节目组的规定,每人只能投票一次,投 票需要在 n 个选手中选出 m 个,这 m 个人每人可以获得一票。A 公司通过秘密 渠道得知了在 A 公司的水军不参与的情况下最终的投票结果,那么 A 公司想要 知道,如果要让公司旗下的艺人获得第一名(不能并列),至少要出动多少名水 军呢?如果无解,输出"Impossible"(不含引号)
输入描述:
第一行输入正整数 T,表示数据的组数。 对于每组数据,第一行为两个正整数 n, m(1<=m<=n<=100000)。 第二行行为 n 个空格隔开的整数。表示第 i 个选手的得票数,且有 1... |1 100000 ii n a
输出描述:
对于每组数据,输出一行,格式为'Case t: x',t 为数据的组号,x 为题目要求 的结果。
输入样例:
2
3 2
2 3 3
4 2
1 2 3 4
输出样例:
Case 1: 4
Case 2: 5
样例解释:
对于第一组数据,投票过程如下:
2 3 3 => 3 4 3 => 4 5 3 => 5 5 4 => 6 5 5
因此至少需要 4 名水军。
分析:
待更新
思路一:
待更新
思路二:
二分(一开始没想到,有思路后代码还是比较好写的。比想象的快,能水过,但是要关闭同步)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, m, a[MAXN];
bool isok(int x,const int *a) {
int a0 = a[0] + x;
LL num = (LL)x*(m-1); //可能爆int
for(int i = 1; i < n; ++i) {
if(a[i] >= a0)
return false;
if(a[i] + x < a0)
num -= x;
else
num -= (a0-1-a[i]);
}
if(num <= 0)
return true;
return false;
}
int main()
{
int T;
ios::sync_with_stdio(false);
cin >> T;
for(int t = 1; t <= T; ++t) {
cin >> n >> m;
int k = 0;
for(int i = 0; i < n; ++i) {
cin >> a[i];
if(a[i] >= a[k])
k = i;
}
if(k == 0)
cout << "Case " << t << ": 0" << endl;
else if(n == m)
cout << "Case " << t << ": Impossible" << endl;
else {
int l = 0, r = 100000, mid;
while(l < r) {
mid = (l+r)/2;
if(isok(mid, a)) {
r = mid;
}
else {
l = mid+1;
}
}
cout << "Case " << t << ": " << l << endl;
}
}
return 0;
}