这道题大体意思是利用一种递归规则生成不同的气球,问在某两行之间有多少个红气球。
我拿到这个题,一开始想的是递归求解,但在如何递归求解的思路上我的方法是错误的。在研读了例题上给出的提示后豁然开朗(顺便吐槽一下算法竞赛第二版在这这道题目上(P246)提示写的有问题,g(k,i)=2g(k-1,i-2^(k-1))+c(k-1) ,他把c(k-1)写成了c(k)...我纠结这个纠结了好久)
根据题目提示,这道题可以用f(k,i)表示k小时后最上边i行的红气球总数
那么我们的答案就可以表示为f(k,b)-f(k,a-1)
如何求f(k,i)?
这里我们通过观察,在k小时后所分成的四部分气球中,最右下角区域的气球是跟其他区域气球不相同的。因此我们可以分成两种情况(i在上半部分和i在下半部分)。
当i<2^(k-1),f(k,i)=2*f(k-1,i)
当i>=2^(k-1),f(k,i)=c(k-1)+f(k-1,i-2^(k-1))
其中c(k-1)代表完整的那部分的红气球数,也就是k-1小时后的红气球数。
由气球构造方式可得递推式:c(k)=3c(k-1),c(0)=1,可知这是个等比数列,求得c(k)=3^k
至此我们就可以得到我们想要的答案了。
第一次,时间超限:
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
long f(long k,long h)
{
if(k==0&&h==1) return 1;
if(h<=0) return 0;
long m=pow(2,k-1);
if(h>m) return 2*f(k-1,m)+f(k-1,h-m);
else return 2*f(k-1,h);
}
int main()
{
int T,i,q=1;
cin>>T;
while(T--)
{
long k,A,B,sum=0;
cin>>k>>A>>B;
printf("Case %d: ",q++);
cout<<f(k,B)-f(k,A-1)<<"\n";
}
return 0;
}
第二次,根据书本改了下,加了个c函数,对了
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
long c(long k)
{
long sum=1;
while(k--)
{
sum*=3;
}
return sum;
}
long f(long k,long h)
{
if(k==0&&h==1) return 1;
if(h<=0) return 0;
long m=pow(2,k-1);
if(h>m) return 2*c(k-1)+f(k-1,h-m);
else return 2*f(k-1,h);
}
int main()
{
int T,i,q=1;
cin>>T;
while(T--)
{
long k,A,B,sum=0;
cin>>k>>A>>B;
printf("Case %d: ",q++);
cout<<f(k,B)-f(k,A-1)<<"\n";
}
return 0;
}