NOJ1052水王争霸——理解

  • Post author:
  • Post category:其他


水王争霸

时间限制(普通/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<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;
}



版权声明:本文为tcherry原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。