#include<iostream> //AC
#include<cstring>
#include<stdio.h>
using namespace std;
long long dp[12][2002],s; //这里要注意是长整形
int main()
{
int t,n,m;
cin>>t;
for(int id=1;id<=t;++id)
{
cin>>n>>m;
memset(dp,0,sizeof(dp));
fill(dp[1]+1,dp[1]+m+1,1);
for(int i=2;i<=n;++i)
for(int j=1;j<=m;++j)
for(int k=1;k<=j/2;++k)
dp[i][j]+=dp[i-1][k];
s=0;
for(int i=1;i<=m;++i)
s+=dp[n][i];
printf("Case %d: n = %d, m = %d, # lists = %lld\n",id,n,m,s);
}
return 0;
}
#include<iostream> //DP,序列中的任意数至少是前面的数的2倍,给出序列的长度和最后一个数的上限,求出组合的可能性
#include<cstring>
#include<stdio.h>
using namespace std;
long long dp[12][2002],s; //这里要注意是长整形
int main()
{
int t,n,m;
cin>>t;
for(int id=1;id<=t;++id)
{
cin>>n>>m;
memset(dp,0,sizeof(dp));
fill(dp[1]+1,dp[1]+m+1,1);
for(int i=2;i<=n;++i)
for(int j=1;j<=m;++j) //dp[i][j]表示某序列有i个数,且最后一个数是j;有多少种可能性
{
if(j%2==0)
dp[i][j]=dp[i][j-1]+dp[i-1][j/2];
else
dp[i][j]=dp[i][j-1];
}
s=0;
for(int i=1;i<=m;++i)
s+=dp[n][i];
printf("Case %d: n = %d, m = %d, # lists = %lld\n",id,n,m,s);
}
return 0;
}
//比如i=4,j=8,表示序列:A1,A2,A3,A4 , 当A4=8时,这4个数的可能组合数,
//转到 dp[i][j]=dp[i][j-1]+dp[i-1][j/2];
//即 dp[4][8]=dp[4][7]+dp[3][4];
//我们知道,dp[4][8]由两部分组成:A4>2*A3 和 A4=2*A3
//而dp[4][7]表示A4=7的可能组合,现在A4=8,明显地 A4>2*A3;
//dp[3][4]表示A3=4的可能组合,显然满足 A4=2*A3;
//如果i=4,j=9, 转到 dp[i][j]=dp[i][j-1];
//即 dp[4][9]=dp[4][8];
//为什么没有dp[3][4]这一项呢,因为dp[4][8]已经包括了 dp[3][4];