Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 25952 | Accepted: 16509 |
Description
Input
Output
Sample Input
1 7 3
Sample Output
8
Source
解析:有些题目可以转化为这样的题目,比如有n个相同的小球,m个相同的盒子,要求每个盒子里面至少有k个小球,问一共有多少种方法:http://blog.csdn.net/duanxian0621/article/details/7864791 方法为:预先在每个盒子里面已经放好k个小球,那么还剩下n-k*m 个小球,然后就转化为了,把n-k*m个相同的小球放入m个相同的盒子里面,有多少种方法。
分情况讨论:a[i][j]表示i个小球放入j个盒子的方法数
① 当放入小球后,球数最少的盒子为空,那么就相当于,把i个小球放入j-1个盒子里面,即a[i][j-1]。
② 当放入小球后,球数最少的盒子不为空,那么说明每个盒子里面都至少有一个小球,那么就预先把每个盒子里面放入一个小球好了,有 a[i-j] [j]。
所以 ,递推公式为 a[i][j]= a[i][j-1]+a[i-j][j],这里是i>=j的。
当i<j的时候,无论怎么放,肯定会存在空盒,不妨先拿走一个空盒(保证有空盒),然后把i个相同的小球放入剩余的j-1个相同的盒子中,有a[i][j-1]种方法,所以a[i][j]=a[i][j-1].
综上:将n个相同的小球放入m个相同的盒子有
当i>=j时,a[i][j]=a[i][j-1]+a[i-j][j];
当i<时,a[i][j]=a[i][j-1],(仔细想想,这里也可以写成a[i][j]=a[i][i],因为a[i][i]=a[i][i+1]=a[i][i+2]=a[i][i+3]……..
初始化a数组代码为:
int a[maxn][maxn];
void prepare()
{
for (int i=0;i<m;i++)
a[i][1]=a[0][i]=1;
for (int i=1;i<maxn;i++)
for (int j=2;j<maxn;j++)
if (j<=i)
a[i][j]=(a[i-j][j]+a[i][j-1])%MOD;
else
a[i][j]=a[i][i]; //其实是a[i][j-1],不过和a[i][i]是一样的。
}
代码:
#include <iostream> using namespace std; const int maxn=11; int a[maxn][maxn]; void init() { for(int i=1;i<=10;i++) a[0][i]=1,a[i][1]=1; for(int i=1;i<maxn;i++) for(int j=2;j<=maxn;j++) if(j<=i) a[i][j]=a[i][j-1]+a[i-j][j]; else a[i][j]=a[i][i]; } int main() { init(); int t,n,m; cin>>t; while(t--) { cin>>n>>m; cout<<a[n][m]<<endl; } return 0; }