水王争霸
总提交:145 测试通过:57
描述
为了丰富校园网络生活,学校 BBS 举行了一次水王争霸赛。比赛开始后,选手们疯狂灌水,都想争取到水王这个荣誉称号。但学校的 BBS 是如此的不堪一击,才 1e-3 秒就超负荷了。
现在需要把选手们灌的水集合起来,降低服务器负荷。
事情是这样得到处理的:
假设每个选手每次灌水量为1L,每灌一次水,服务器就用一个容量为无限的虚拟容器收集这1L水。
最后服务器中有N个容器收集了水。而服务器最多能负载K个装了水的容器。但是,服务器只有一种自救措施:就是把两个装了同样多水的容器合并到这两个容易中的其中一个,另一个空了的直接free它。
然而不能排除这种情况的存在:通过自救方式,仅由选手们灌好的N容器水不能恰恰好收集成不超过K个非空容器来装。比如,N=3,K=1的时候,无论如何收集,都只能得到容量分别为1L和2L的两个非空容器,不可能得到符合要求的1个非空容器。幸运的是,服务器还有一点点空间,允许你再灌若干次水,使得 BBS 恢复正常。拯救服务器中的虚拟世界这个艰巨而光荣的任务就落到你身上了。
输入
有1000组输入数据,每组输入数据一行,包含两个正整数N、K,其中N不超过10,000,000,K不超过1,000。
输出
输出最少需要继续灌水的次数,如果不可能拯救服务器,输出-1。
样例输入
3 1
13 2
1000000 5
100 100
样例输出
1
3
15808
0
题目来源
wwm
分析:难点在于题目不是很好理解~
实际含义:N代表一共有多少人灌了水,每个人灌水就相当于一个1L水的容器。每2个装了相同多的水可以合并成1个容器,即2个变1个,少了一个容器。
最后的容器要 ≤ K。
举例:N=3,K=1的时候,即有3个人灌水,每人灌水1L,有3个容器。则其中2个1L的容器可以合并成2L的,还剩下一个1L的,现在总共有2个容器,且不能再合并了,所以不满足 ≤ 1。
解决方法是“我”可以再灌若干次水使得最后的容器总数 ≤ K。以上例来说,我再灌1次水,即又多了一个1L的容器。则此时2个1L的又能合并成一个2L的,之后又能和最先合并成的2L合并成4L的容器。最后总共1个容器。满足条件,所以输出最少需要继续灌水的次数为1。
So:2^n个1L能合并成1个容器,且容量为2^n L。
例如输入
13 2
时,13=2^3+2^2+1,所以现在需要3个容器,但是3 > 2,所以再灌水1次,13=2^3+2^2+2^1,Again,13=2^3+2^2+2^1+1,Again,13=2^3+2^3=2^4。Done!
所以创建数组sjh[]:sjh[0] = 1,sjh[1] = 2,sjh[2] = 4,sjh[3] = 8。。。
数组的个数即为需要的容器数量。关键在于我每次灌水之后的合并~
了解des!开动~就是奇偶啊,倍数啥的~
注意输入数据有1000组。
#include<stdio.h>
//水王争霸
int main()
{
int counts = 1000, n, k, sjh[100], sum, num, V;
while(counts --)
{
sum = 0; // init
num = 0; V = 1; // num个容器, V多少升
scanf("%d%d",&n,&k); // n个1L
while(n)
{
if(n % 2 == 1)
sjh[num++] = V;
n /= 2;
V *= 2;
}
int i = 0;
while(num > k)
{
sum += sjh[i+1] - sjh[i];
sjh[i] = sjh[i+1];
while(sjh[i] == sjh[i+1]) // 循环合并
{
for(int j=i+1;j<num-1;j++) // 减小数组
sjh[j] = sjh[j+1];
num --;
sjh[i] *= 2;
}
}
printf("%d\n",sum);
}
return 0;
}