以下是题目:
首先为表示方便,以左代下,以右代上,对此题进行分析:
在此先假设 GetGold( n,i)表示:n级硬币塔从下往上数i步所经过的金币数
题中给出的k层硬币塔的结构是这样的:
银币 k-1级硬币塔 k个金币 k-1级硬币塔 银币
我们可以类似的将该结构看成一个数轴,第一个银币左边的位置为原点。
为表示端点的值,我们假设floor(n) 表示n级硬币塔的层数
而题目想给出i步,计算从下往上有几个金币,对此,显然有以下7种情况:
①i<=0时,显然 GetGold( n,i)为0;
②i=1时, 如果n=0,则GetGold (n,i)为1,若n>=1,则GetGold(n,i)为0;
③1<i<=1+floor(n-1)时,GetGold(n,i) 就相当于减去最左边的银币后,对n-1级硬币塔进行i-1步检索,也就有 GetGold(n,i) = GetGold(n-1,i-1);
④1+floor(n-1)<i<=1+floor(n-1)+k时,此时经过的金币数为n-1级硬币塔的金币数加上(k-i)个金币,即
GetGold(n,i) = GetGold(n-1,floor(n-1) ) +(k-i);
⑤1+floor(n-1)+k<=i <= 1+2*floor(n-1)+k时,此时情况 其实是③④的结合,此时经过的金币数为n-1级硬币塔的金币数加上k个金币,对n-1级硬币塔进行i-1-floor(n-1)-k步检索,也就有
GetGold(n,i) = GetGold(n-1,floor(n-1))+k+GetGold( n-1,i-1-floor(n-1)-k);
⑥i=1+2*floor(n-1)+k+1时,此时相当于在⑤后多数了一步,并且最后数的硬币刚刚好是最后一个银币,即有GetGold(n,i) = GetGold(n-1,floor(n-1))+k+GetGold( n-1,i-1-floor(n-1)-k-1);
⑦i>1+2*floor(n-1)+k+2 时,由题可得,floor(n) = 1+2*floor(n-1)+k+2,故此时有
i>floor(n),因此 GetGold(n,i) = GetGold(n, floor(n) )。
对以上的情况进行简要综合分析,
I.当 i<0时,GetGold(n,i) = 0;
II.当i> =floor(n) 时, GetGold(n,i) = GetGold(n,floor(n) );
根据上述两种情况,当0<i < floor(n) 时,
GetGold(n,i) = GetGold(n-1, i-1) + (i-floor[n-1]-1)<=0 ? 0:(i-floor[n-1]-1)>=n?n:(i-floor[n-1]-1) + GetGold(n-1,i-floor[n-1]-1-n )
在此我们对此进行上述该式子进行分析:
GetGold(n-1, i-1) 这一项表示,第一个n-1级硬币塔的走i-1步的金币数,显然i-1<floor(n) 时能正常表示,i-1>=floor(n)时,可由II式子转化成GetGold(n,floor(n) );
(i-floor[n-1]-1)<=0 ? 0:(i-floor[n-1]-1)>=n?n:(i-floor[n-1]-1)这一项表示,当i<=floor[n-1]+1即为情况③时,经过的中间层(k个金币层)只有0个金币;而当i>=n+floor[n-1]+1即为情况⑤时,经过的中间层有k个金币;当floor[n-1]+1<i<n+floor[n-1]+1即为情况④时,经过的中间层有(i-floor[n-1]-1)个金币。
GetGold(n-1,i-floor[n-1]-1-n)这一项表示,第二个n-1级硬币塔,在走完前面 一个银币,一个n-1级硬币塔,k个金币后,还需走的i-floor[n-1]-1-n步在n-1级硬币塔中经过的金币数,
当i-floor[n-1]-1-n>floor[n-1]时,由Ⅱ可转变成GetGold(n-1,floor(n-1));
当i-floor[n-1]-1-n<=floor[n-1]时,由Ⅰ将直接返回0;
综上所述,我们需要先根据递归公式,floor[n] = 2*Getfloor(n-1)+2+n,推出n级硬币塔的层数;
接着对GetGold(n,i)设计分段函数:
当n=0时,若i>0,则GetGold(n,i) = 1;反之,GetGold(n,i) = 0;
当 i<=0时,GetGold(n,i) = 0;
当0<i<floor(n)时,GetGold(n,i) = GetGold(n-1, i-1) + (i-floor[n-1]-1)<=0 ? 0:(i-floor[n-1]-1)>=n?n:(i-floor[n-1]-1) + GetGold(n-1,i-floor[n-1]-1-n )
当i> =floor(n) 时, GetGold(n,i) = GetGold(n,floor(n) );
为避免重复调用函数,我们可以通过哈希表记录已经得出结果的GetGold(n,i)的值,以期望下次需要求得GetGold(n,i)的值时不必继续递归,直接返回结果。
那么以下便是代码:
#include<iostream>
#include <vector>
#include <map>
using namespace std;
map < pair< long long, long long> , long long> mp;
vector< long long> floor;
long long Getfloor( long long n){
//初值条件
if( n == 0) {
floor[n] = 1;
return floor[n];
}
//递推公式
floor[n] = 2*Getfloor(n-1)+2+n;
return floor[n];
}
long long GetGold( long long n, long long i){
if( i<=0) return 0;
if(n==0) return 1;
if( mp.count( {n,i}) ) return mp[ {n,i}];
if( i>floor[n]) return GetGold(n,floor[n]);
mp[{n,i}] = GetGold(n-1,min(floor[n-1],i-1))+GetGold(n-1,max(i-floor[n-1]-1-n,(long long)0));
mp[{n,i}] += (i-floor[n-1]-1)<=0 ? 0:(i-floor[n-1]-1)>=n?n:(i-floor[n-1]-1);
return mp[ {n,i}];
}
int main( )
{
long long n,i;
cin>>n>>i;
floor.resize(n+1);
Getfloor(n);
cout<<GetGold(n,i)<<endl;
floor.clear();
return 0;
}