[codeforces 1348D] Phoenix and Science 从两个极端结果出发,找到中间结果

半世苍凉 提交于 2020-05-03 20:17:05

Codeforces Round #638 (Div. 2)  比赛人数15215

[codeforces 1348D]   Phoenix and Science   从两个极端结果出发,找到中间结果

总目录详见https://blog.csdn.net/mrcrack/article/details/103564004

在线测评地址https://codeforces.com/contest/1348/problem/D

Problem Lang Verdict Time Memory
D - Phoenix and Science GNU C++17 Accepted 31 ms 0 KB

信心很重要,没有信心,这样的问题未必能解决,问题解决得越多,内心越强大。

编码过程中,遭遇了一次WA,一次TLE.均靠如下极端数据的测试通过得以解决。极端数据是对程序的最大考验

Input:
1 1000000000
29
Output:
1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 194693633

部分样例模拟如下,注意,该题,无需浮点运算,该题全程是整数运算。

Input:
3
9
11
2
Output:
3
1 1 0 
3
1 2 0 
1
0

9
3
1 1 0
1.第一个极端情况,全程,所有数量一直在分裂
第1天结束后数量(1/2+1)*2=1+1*2=3
第2天结束后数量((1+1*2)/4+1)*4=1+1*2+1*4=7
第3天结束后数量((1+1*2+1*4)/8+1)*8=1+1*2+1*4+1*8=15
......
第i天结束后数量,根据等比数列求和公式,可得2^(i+1)-1

很明显7<9<15,在极端分裂的情况下,需要3天

2.第二个极端情况,全程,所有数量都不分裂
第1天结束后数量1+1=2
第2天结束后数量2+1=3
第3天结束后数量3+1=4
......
第i天结束后数量,可得i+1

3.从第二个极端情况出发,开始寻找,中间结果9
还剩9-4=5数量需要分裂来实现,4的由来:第3天结束后数量3+1=4

第1天最大可分裂数量是1,若发生1次分裂(此次分裂之后,不再分裂),
到第3天可使数量增加1*(3-1+1)=3,还剩5-3=2数量需要分裂来实现,
故第1天,需要1分裂

紧接上面结果,第2天最大可分裂数量是2,若发生1次分裂(此次分裂之后,不再分裂),
到第3天可使数量增加1*(3-2+1)=2,还剩2-2=0数量需要分裂来实现
故第2天,需要1分裂

因还剩0数量需要分裂来实现,故第3天,需要0分裂

输出结果
3
1 1 0

AC代码如下

#include <stdio.h>
#define maxn 32
int mx[maxn],cnt[maxn],can[maxn];//can[i]记录第i天可以发生分裂的数量,第i天发生分裂数量不能超过这个值。
int main(){
	int t,n,i,a,j;
	mx[0]=2;
	for(i=1;i<=30;i++)mx[i]=mx[i-1]*2;
	for(i=1;i<=30;i++)mx[i]-=1;//mx[i]第i天,对应的最大数量
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		if(n==2){printf("1\n0\n");continue;}//特判
		for(i=1;i<=30;i++)cnt[i]=0;//记录第i天需要分裂的数量,注意i<=30而不是i<=n
		for(i=1;i<=30;i++)
			if(mx[i]>=n)break;
		a=i;//找到需要的最小天数
		printf("%d\n",a);
		n-=a+1;//扣除整个过程一次都不分裂的情况。
		can[0]=1;
		for(i=1;i<=a;i++){
			can[i]=can[i-1];//从前一天继承下来的可以分裂数量
			j=n/(a-i+1);//j表示发生分裂数量
			if(j>can[i])j=can[i];//超出了可分裂数量限制,修正数据
			n-=j*(a-i+1),can[i]+=j,cnt[i]=j;//第i天的1次分裂(这次分裂之后,若不分裂),会导致到达a天后的数量增加a-i+1;
		}
		for(i=1;i<=a;i++)
			printf("%d ",cnt[i]);
		printf("\n");
	}
	return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!