思路
典型的HZB不会做的题目
这道题其实跟洛谷的放苹果一模一样,我们可以看作是n个相同的球,放在m个相同的盒子里,且盒子不可以为空进行m次计算,将m,m-1,m-2,m-3……0的值加在一起。因为数据较小,也可以用深搜做。这里采用的是动态规划方法,用递归函数去实现。
我们知道,当查克拉的能量<0时,它的方案数显然为0。(当然,如果在循环中就可以不用这一条,因为C++没有下标为负数的数组,不过这里用的是递归的方法,所以要加上这一条)
先定义一个递归函数f(int m,int n)
当没有查克拉的能量或者只有一个影分身时,它的方案数为1。
当查克拉的能量<分成分身个数时,它的方案数为f[m][m]。
当查克拉的能量>=分成分身个数时,它的方案数相当于f[m-n][n]+f[m][n-1],也就是少了n个能量分成n个分身的方案数+能量不变少一个分身的方案数。
比如有一个3个能量,分成二个分身,它的方案数相当于1个能量分成2个分身+3个能量分成1个分身的方案数。也就是2,分别是1,2和3,0;
动态转移方程:
if (m<0) return 0;
if (m==0||n==1) return 1;
if (m<n) return f(m,m);
if (m>=n) return f(m-n,n)+f(m,n-1);//其实前面的判断可以不要,因为m不是<n就是>=n,这里加上去是为了方便理解。
这就有了后面的代码
#include<cstdio>
#include<cstring>
#define r(i,a,b) for(int i=a;i<=b;i++)//循环
using namespace std;
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}//最大值和最小值函数
int maxn=0,minn=0,ans=0;//我每次做动态规划题都会这样留三个变量。。。
int t,n,m;//t组测试数据,m点能量,n个分身
int f(int m,int n)//前面解释过了
{
if (m<0) return 0;
if (m==0||n==1) return 1;
if (n>m) return f(m,m);
if (m>=n)return f(m-n,n)+f(m,n-1);
}
void read(int &f)//输入流
{
f=0;bool d=0;char c;
while (c=getchar(),c<'0'||c>'9') if (c=='-') d=1;f=f*10+c-48;
while (c=getchar(),c>='0'&&c<='9') f=f*10+c-48;
if (d) f*=-1;
}
void write(int x)//输出流
{
if (x) write(x/10);else return;
putchar(x%10+48);
}
void sc(int x,int y)//因为输出流没办法输出0,所以就有了这个过程。y为避免输出最后一个换行,其实这个也没用。。。强迫症。。。
{
if (!x)
putchar(48);
write(x);
if (t-y) putchar(10);
}
int main()
{
read(t);
r(i,1,t)
{
read(m);read(n);
sc(f(m,n),i);
}
}
递归函数的优势是可以少开一个数组,缺点是速度慢一点,当然也可以加上记忆化,因为它有t组测试数据,这样就可以减少不少的时间,不过要多开一个数组。
#include<cstdio>
#include<cstring>
#define r(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int maxn=0,minn=0,ans=0;
int t,n,m;int d[101][101];//保存之前已经算过的结果
int f(int m,int n)
{
if (d[m][n]) return d[m][n];//如果这个点已经有值了直接返回
if (m<0) return 0;
if (m==0||n==1) {d[m][n]=1;return 1;}
if (n>m) {int t=f(m,m);d[m][n]=t;return t;};
if (m>=n){int t=f(m-n,n)+f(m,n-1);d[m][n]=t;return t;}
}
void read(int &f)
{
f=0;bool d=0;char c;
while (c=getchar(),c<'0'||c>'9') if (c=='-') d=1;f=f*10+c-48;
while (c=getchar(),c>='0'&&c<='9') f=f*10+c-48;
if (d) f*=-1;
}
void write(int x)
{
if (x) write(x/10);else return;
putchar(x%10+48);
}
void sc(int x,int y)
{
if (!x)
putchar(48);
write(x);
if (t-y) putchar(10);
}
int main()
{
read(t);
r(i,1,t)
{
read(m);read(n);
sc(f(m,n),i);
}
}