题目:
给出四堆石子,石子数分别为a,b,c,d。规定每次只能从堆顶取走石子,问取走所有石子的方案数。
样例:
3 5 4 2
输出:
2522520
数学垃圾硬是乱dp:
/**
这就是数学垃圾的下场!!!!!
dp[i][j]表示只有两堆石子时有多少种取法。
f[i][j]表示把长度为j的序列 插入到长度为i的序列中 而且序列 i,j都保持原有得次序 的方法有多少种。
则 ans = f[a+b][c+d]*dp[a][b]*dp[c][d];
*/
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn = 500;
const int inf = 1e9;
const ll mod = (1e9+7);
ll dp[maxn+5][maxn+5],f[maxn*2+5][maxn*2+5];
ll dfs(int a,int b)
{
if(dp[a][b]!=-1) return dp[a][b];
if(a==0&&b==0) return (dp[a][b] = 1);
dp[a][b] = 0;
if(a>0) dp[a][b] = (dp[a][b]+ dfs(a-1,b))%mod;
if(b>0) dp[a][b] = (dp[a][b]+ dfs(a,b-1))%mod;
return dp[a][b]%mod;
}
ll DFS(int a,int b)
{
if(f[a][b]!=-1) return f[a][b];
if(a==0||b==0) return (f[a][b] = 1);
f[a][b] = 0;
if(b>0) f[a][b] = (f[a][b] + DFS(a,b-1))%mod;
if(a>0) f[a][b] = (f[a][b] + DFS(a-1,b))%mod;
return f[a][b];
}
int main()
{
memset(dp,-1,sizeof(dp));
memset(f,-1,sizeof(f));
int a,b,c,d;
while(~scanf("%d %d %d %d",&a,&b,&c,&d))
{
int sum0 = a+b,sum1=c+d;
ll w1= dfs(a,b), w2 = dfs(c,d);
ll w = DFS(sum0,sum1);
ll ans = (w*w1%mod*w2%mod)%mod;
printf("%lld\n",ans);
}
return 0;
}
被自己菜醒的组合数学:
可以到着思维:把石头取出 等价 把石头放回,ans = C(a, a+b+c+d)*C(b, b+c+d)*C(c, c+d) = (a+b+c+d)!/(a!b!c!d!).
也可以顺着来,把石头取出当是每堆的石头顺序是固定的:大神分析的很好:点击打开链接