题目:
给出四堆石子,石子数分别为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!).
也可以顺着来,把石头取出当是每堆的石头顺序是固定的:大神分析的很好:点击打开链接