• UVALive 6486 Skyscrapers 简单动态规划


    题意:

      有N个格子排成一排,在每个格子里填上1到N的数(每个只能填一次),分别代表每个格子的高度。现在给你两个数left和right,分别表示从左往右看,和从右往左看,能看到的格子数。问有多少种情况。

    数据范围: N<5000;

    思路:

      首先枚举最高的一块,在最高的格子的后面的格子都一定会被挡住。所以,除了最高的那一格之外,从左边能看到的格子,从右边一定看不到;从右边能看到的也是一样。

      因此,除了最高的那个格子,左边的是否能被看见,和右边的无关。所以,我们可以以最高的格子为界,把这一排格子分成左右两部分。

      在这样子,我们就可以把左边和右边看成是一种情况:把n个高度不等的方块排成一列,要求从前面只能看到k个,有多少种。

        我们把上面问题(n个格子,看见k个)的结果记为f[n, k]。

        对于上面那个问题,我们考虑两种情况:最高的放在最后,和最高的不放在最后。 

      1. 如果最高的放最后,因为最高的一定不会被挡住,所以,前面n-1个格子,需要被看见k-1个。

      2. 如果最高的不放在最后,那么,最后一格一定会被挡住(因为最高的在它前面,而且会挡住他),所以前面n-1个格子,仍然需要被看见k个。

    上面第一种,情况只有一种;而第二种情况有n-1种(把n-1个不是最高的中任意一个放到最后都满足)。

      所以 f[n, k] = f[n-1, k-1] + (n-1)*f[n-1, k]。

      另外就是边界情况,k=1的时候,这样一定就是最高的放最前面,后面随便放,所以就是 f[n, 1] = (n-1)!。

      还有就是,组合数可以用杨辉三角来求,这个是学弟说的,本人数学功底太差 0 0、

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 
     8 typedef long long ll;
     9 const int MAXN = 5005;
    10 const ll MOD = (ll)1e9+7.0;
    11 
    12 
    13 ll dp[MAXN][MAXN];
    14 ll C[MAXN][MAXN];
    15 ll ni[MAXN];
    16 
    17 int n, l, r;
    18 ll ans;
    19 
    20 int main()
    21 {
    22     #ifdef Phantom01
    23         freopen("in.txt", "r", stdin);
    24         freopen("my.out", "w", stdout);
    25     #endif // Phantom01
    26 
    27     dp[0][0] = dp[1][1] = 1;
    28     for (int i = 1; i < MAXN; i++)
    29         dp[0][i] = dp[i][0] = 0;
    30     for (int i = 2; i < MAXN; i++)
    31         dp[i][1] = (dp[i-1][1]*(i-1))%MOD;
    32     for (int i = 1; i < MAXN; i++)
    33         for (int j = 2; j < MAXN; j++)
    34             dp[i][j] = (dp[i-1][j-1]+(dp[i-1][j]*(i-1))%MOD)%MOD;
    35 
    36     for (int i = 0; i < MAXN; i++) {
    37         C[i][0] = 1;
    38         for (int j = 1; j <= i; j++)
    39             C[i][j] = (C[i-1][j]+C[i-1][j-1])%MOD;
    40     }
    41 
    42     while (scanf("%d%d%d", &n, &l, &r)!=EOF) {
    43         if (!(n||l||r)) break;
    44         ans = 0;
    45         if ((l+r)<=(n+1)) {
    46             for (int i = l; i <= (n-r+1); i++) {
    47                 ans = (ans+( ( (dp[i-1][l-1]*dp[n-i][r-1])%MOD) *C[n-1][i-1])%MOD)%MOD;
    48             }
    49         }
    50         printf("%d
    ", (int)ans);
    51     }
    52     return 0;
    53 }
    View Code
  • 相关阅读:
    origin 8.5 曲线拟合,延长曲线范围
    赤手空拳编写C#代码
    Vmware 10安装MAC OS X 10.9备忘
    Contest 1445
    Contest 1428
    Contest 1435
    Contest 991
    CSP-SJX2019 解题报告
    【BZOJ4817】【SDOI2017】树点染色
    codeforce 804B Minimum number of steps
  • 原文地址:https://www.cnblogs.com/Phantom01/p/3618324.html
Copyright © 2020-2023  润新知