Skyscrapers 组合数学
2014-04-03 21:03
274 查看
题目大意:对于一行n个数的数组,从左边(必须包含第一个)的最长递增长度为left,从右边为right,求符合条件的情况数。
例1:1 3 2和 2 3 1
例2:4 1 2 3 和 4 2 1 3
1.由于最高的那个一定能被看到,所以可以枚举highest的位置。
设dp[i][j]为i个数有j个递增的种数
2.对于位置i,从n-1个数里选i-1个数放左边,并且左边有left个递增,C(n-1,i-1)*dp[i-1][left-1];
剩下的数在右边,并且有right个递增, 再*dp[n-i][right-1]。
答案就是 sum(C(n-1,i-1)*dp[i-1][left-1]*dp[n-i][right-1]) ;
由于左右个数要足够,所以 i=[left,n+1-right];
那么问题就是如何求dp[i][j]了。
3.对于dp[i][j],分两种情况。dp[i-1][j-1] 那么最大的那个放最右。dp[i-1][j] 那么最大的那个放最右,然后i-1个选一个放最大的后面。
有状态转移为dp[i][j]=dp[i-1][j-1]+dp[i-1][j]*(i-1)
4.根据C(i,j)=C(i-1,j-1)+C(i-1,j)递推求出c[i][j]。再注意MOD,即可求出答案。
题目地址
源码:
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; typedef long long LL; const int MOD=1e9+7,N=5001; LL dp ,c ; void init() { //c[i][j]表示i个中取j个的种数 for(int i=0;i<N;i++) c[i][i]=c[i][0]=1; for(int i=2;i<N;i++){ for(int j=1;j<i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD; } //dp[i][j]表示 i个里j个递增的种数 dp[0][0]=1; for(int i=1;i<N;i++){ for(int j=1;j<=i;j++) dp[i][j]=((i-1)*dp[i-1][j]%MOD+dp[i-1][j-1])%MOD; } } void solve(int n,int left,int right){ LL ans=0; //枚举最高的位置--最高的肯定能被看到 for(int i=left;i<=n-right+1;i++){ ans=(ans+((c[n-1][i-1]*dp[i-1][left-1])%MOD)*dp[n-i][right-1]%MOD)%MOD; } printf("%I64d\n",ans); } int main(){ init(); int n,left,right; while(cin>>n>>left>>right&&n||left||right) solve(n,left,right); return 0; }
相关文章推荐
- HDUOJ---三角形(组合数学)
- POJ 3286- How many 0's?(组合数学_区间计数)
- Game of Connections -组合数学中的计数问题
- 组合数学 - 置换群的幂运算 --- poj CARDS (洗牌机)
- HDU 4869 Turn the pokers【组合数学】
- hdu4532 组合数学+dp
- hdu 3037 Saving Beans(组合数学)
- Codeforces 615D Multipliers 【组合数学】
- C/C++面试之算法系列--如何利用数学思想解1/2/5组合问题
- 递推与组合数学基础,有助于理解
- POJ 2355 Find a multiple(组合数学-抽屉原理)
- Locked Treasures(组合数学思维)uva 6873
- 数学 ( 排列组合 )——HDU 5194
- 组合数学基本工具-- 排列与组合以及简单公式
- 3505: [Cqoi2014]数三角形 组合数学
- FZU 1876 组合数学
- 组合数学_学习笔记(四)
- Vijos 1943-上学路上【组合数学】
- 一些组合数学
- POJ1942-Paths On a Grid-组合数学