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<stdio.h>
#include<cmath>
int main()
{
int k = 1, t ;
scanf("%d",&t);
while(k++<=t)
{
int n, m;
scanf("%d %d",&n,&m);
int ticket[100005];
for(int i = 1;i<=n;i++)
scanf("%d",ticket+i);
int j = 1, max = ticket[1];
for(int i = 2;i<=n;i++) //判断是否有别的值比ticket[1]大,并找出来
if(ticket[i]>=max)
{
j = i;
max = ticket[i];
}
if(j==1) //ticket[1]就是最大的
{
printf("Case %d: 0\n",k-1);
continue;
}
if(n==m) //n==m且ticket[1] 不是最大的,则无解
{
printf("Case %d: Impossible\n",k-1);
continue;
}
int a = max-ticket[1]+1; //为了比最大的人票数多,至少要a个水军参加投票
int count = a*m-a; //count 为a个水军投票的总数,去掉给ticket[1]的票
//把count个票往别的选手上分,但要使得其他人的票数最多为max(ticket[1]-1) ,
for(int i = 2;i<=n;i++)
{
if(ticket[i]>=ticket[1]) //最多只能给(max - ticket[i])个,使的他的票数为max
count = count - (max-ticket[i]);
else
count -= a;
}
if(count<=0) //如果此时票数分完了,也就是已经够了(上面已经保证每一个都不大于ticket[1])
{
printf("Case %d: %d\n",k-1,a);
continue;
}
int i;
//如果不够,继续加水军
for(i = 1;(1.0*i*m+count-i)/(n-1)>i;i++); //i个水军吧票数给1号i票之后,把剩下的票数平分给其他的n-1个人,如果他们平均得到的票数<=i(也就是其他人票数要始终比1号少一个或多个),此时就已经够了
//i = ceil(count*1.0/(n-m)); 上面的for循环可以简化为这个试子
printf("Case %d: %d\n",k-1,a+i);
}
}