NOJ1052水王争霸——理解

水王争霸

时间限制(普通/Java):1000MS/3000MS          运行内存限制:65536KByte
总提交: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

//水王争霸

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





你可能感兴趣的:(C,ACM)