zoukankan      html  css  js  c++  java
  • Codeforces Round #100 E. New Year Garland (第二类斯特林数+dp)

    题目链接:

    http://codeforces.com/problemset/problem/140/E

    题意:

    圣诞树上挂彩球,要求从上到下挂(n)层彩球。已知有(m)种颜色的球,球的数量不限。

    要求结果对(p)取模。然后给你(n)个数,表示第 (i) 根绳长 (l_i),也就是要挂 (l_i) 个球。

    (1.)要求每根绳上相邻彩球颜色不同。

    (2.)相邻的绳子上挂的彩球种类不能相同。

    题解:

    我们先解决子问题,先考虑第 (i) 层上能放多少个球,(a[i][j])表示长为(i)的绳子上放(j)种球的方案数,考虑的其实就是(j)种小球往(i)个无编号的盒子里放,每个盒子放一个,相邻盒子小球不一样,

    (a[i−1][j−1])表示(i−1)个盒子放(j−1)种小球,变成 (i) 盒子 (j)小球,就是新添加一个小球放进一个新的盒子里。

    (a[i−1][j])表示(i−1)个盒子(j)种小球,新添加一个盒子时可以放除了相邻盒子中的小球外任意小球,即 ((j−1)) 个。

    所以,(a[i][j]=a[i−1][j−1]+a[i−1][j]∗(j−1))。显然这就是第二类斯特林数。

    我们再考虑 (dp[i][j])表示在第(1)(i−1)根绳子排列合法的情况下,第(i)根绳子用 (j) 种小球的合法方案数。

    那么,(dp[i][j] = sumlimits_{i = 1}^{m}sumlimits_{j = 1 }^{l[i]} [dp[i-1][j]*(绳子i上放j 种小球的合法方案数)-(绳子i与绳子i-1用同样小球的方案数)(i > 1)(j <= l[i-1])])

    所以,

    绳子(i)上放(j)种小球的合法情况有: (a[i][j]*A_k^j) (其中(k) 为可以选择的颜色数量)。

    绳子(i)与绳子(i-1)用同样小球的方案数就是:(dp[i-1][j]*a[i][j]*A_j^j)

    最后把该预处理的都预处理一下就可以了。

    (dp) 那个数组好难开。。。最后(resize)一下过了....没有(c++11)我可能啥都写不出来....

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    const double pi = acos(-1.0);
    const double eps = 1e-9;
    const int maxn = 1001000;
    
    int l[maxn],a[5201][5201],fac[5201],rfac[5201];
    //int dp[5201][5201];
    std::vector<int> dp[maxn];
    
    int main(int argc, char const *argv[]) {
      int n,m,p;
      std::cin >> n >> m >> p;
      int sz = 0 ;
      for(int i=1;i<=n;i++) {
        std::cin >> l[i];
        //sz = max(l[i],sz);
        dp[i].resize(l[i]+1);
      }
      //  vector<vector<int>> dp(sz + 1, vector<int>(sz + 1, 0));
      fac[0] = 1;
      rfac[0] = 1;
      for(int i=1;i<=5010;i++) {
        fac[i] = 1LL * fac[i-1] * i % p;
        rfac[i] = 1LL * rfac[i-1] * (m - i + 1) % p ;
      }
      a[0][0] = 1;
      for(int i=1;i<=5010;i++) {
        for(int j=1;j<=i;j++) {
          a[i][j] = (a[i-1][j-1] + 1LL * a[i-1][j] * (j-1) % p) % p;
        }
      }
      int sum = 1;
      int ans = 0;
      for(int i=1;i<=n;i++) {
        for(int j=1;j<=l[i];j++) {
          dp[i][j] = 1LL * sum * rfac[j] % p * a[l[i]][j] % p;
          if(i > 1 && j <= l[i-1]) {
            dp[i][j] = (dp[i][j] - 1LL * dp[i-1][j] * a[l[i]][j] % p * fac[j] % p + p) % p;
          }
          ans = (ans + dp[i][j]) % p;
        }
        sum = ans;
        ans = 0;
      }
      std::cout << sum << '
    ';
      return 0;
    }
    
    
  • 相关阅读:
    初谈DHCP中继原理和配置
    css3渐变之linear-gradient与-webkit-linear-gradient写法异同
    mac svn 更新到新版本1.8
    mac显示所有文件、不产生.DS_Store文件
    mac自定义安装nodejs步骤
    nodejs 80端口监听失败及NODE_PATH不起作用的问题
    一种javascript链式多重继承的方式(__proto__原型链)
    apk反编译、smali修改、回编译笔记
    启用“关闭自动根证书更新”,解决Windows系统各种卡顿的问题(Visual studio 卡、远程桌面mstsc卡、SVN卡)
    SQL查询中关于索引使用的笔记
  • 原文地址:https://www.cnblogs.com/LzyRapx/p/8064927.html
Copyright © 2011-2022 走看看