zoukankan      html  css  js  c++  java
  • 【做题】TCSRM592 Div1 500 LittleElephantAndPermutationDiv1——计数&dp

    题意:定义函数(f(A,B) = sum_{i=1}^n max(A_i,B_i)),其中(A)(B)都是长度为(n)的排列。给出(n)(k),问有多少对((A,B))满足(f(A,B)geq k)。对(10^9 + 7)取模。

    (n leq 50)

    首先,可以直接钦定(A)(1,2...n)的一个排列,即对于所有(i)满足(A_i = i),最后答案再乘以(n!)

    然后就变成了对(B)这一个排列的计数问题。考虑函数(f)中有贡献的只有较大值,我们不必计较其中的较小值具体是什么。这启发我们在dp时把较小的数分配到较大的位置,并记录其数量。

    因此,我们令状态(dp_{i,j,k})表示当前从(1)开始放置了(i)个数,其中有(j)个数被分配到后面的位置,并且当前得到的函数值为(k)。当然,这里的函数值只包括(max(A_s,B_s) leq i)的值,这样便于转移。同样地,当我们把一个数分配到后面的位置上时,我们不能轻易乘上一个系数(可分配的位置个数),因为分配不同的位置对答案的贡献不同。

    那么,对于第(i+1)个数以及位置,就有下面这些情况:

    • (i+1)放在第(i+1)个位置。那么,j不变,k+=i,且只有一种方案。
    • (i+1)放在前(i)个位置,第(i+1)个位置放了小于(i+1)的数。那么,j-=1,k+=2*i,且第(i+1)个数有(j)个位置可放,第(i+1)个位置也有(j)个数来放。因此有(j^2)种方案。
    • (i+1)放在前(i)个位置,第(i+1)个位置放了大于(i+1)的数。那么,j不变,k+=i,且第(i+1)个数有(j)个位置可放,放在第(i+1)个位置的数未确定。因此有(j)种方案。
    • (i+1)放在后面的位置,第(i+1)个位置放了小于(i+1)的数。那么,j不变,k+=i,且(i+1)未确定放在哪个位置,第(i+1)个位置有(j)个数来放。因此有(j)种方案。
    • (i+1)放在后面的位置,第(i+1)个位置放了大于(i+1)的数。那么,j+=1,k不变,且(i+1)放在哪里,第(i+1)个位置放什么都是为确定的。因此只有一种方案。

    时间复杂度(O(n^4))

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAXN = 55, MOD = (int)(1e9 + 7);
    int dp[2][MAXN][MAXN * MAXN];
    class LittleElephantAndPermutationDiv1 {
    public:
      int getNumber( int N, int K );
    };
    int LittleElephantAndPermutationDiv1::getNumber(int N, int K) {
      int p = 1;
      memset(dp,0,sizeof dp);
      dp[0][0][0] = 1;
      for (int i = 1 ; i <= N ; ++ i, p ^= 1) {
        memset(dp[p],0,sizeof dp[p]);
        for (int j = 0 ; j < i ; ++ j) {
          for (int k = 0 ; k <= 2500 ; ++ k) {
            if (!dp[p^1][j][k]) continue;
            (dp[p][j][k+i] += dp[p^1][j][k]) %= MOD;
            if (j > 0) (dp[p][j-1][k+i+i] += 1ll * j * j * dp[p^1][j][k] % MOD) %= MOD;
            if (i < N) (dp[p][j][k+i] += 1ll * j * dp[p^1][j][k] % MOD) %= MOD;
            if (i < N) (dp[p][j][k+i] += 1ll * j * dp[p^1][j][k] % MOD) %= MOD;
            if (i < N) (dp[p][j+1][k] += dp[p^1][j][k]) %= MOD;
          }
        }
      }
      p ^= 1;
      int ret = 0;
      for (int i = K ; i <= 2500 ; ++ i)
        (ret += dp[p][0][i]) %= MOD;
      for (int i = 1 ; i <= N ; ++ i)
        ret = 1ll * ret * i % MOD;
      return ret;
    }
    

    小结:这个dp的特色在于确定一个排列,从而同时对位置和值的分配dp,这样可以解决一些较复杂的问题。

  • 相关阅读:
    会声会影教程之图片音乐相册制作
    js校验表单后提交表单的三种方法总结(转)
    如何避免后台IO高负载造成的长时间JVM GC停顿(转)
    nginx的upstream目前支持5种方式的分配(转)
    Nginx配置文件详细说明(转)
    如何将character_set_database latin1 改为 gbk(转)
    Maven打包可执行Jar包方式
    六种微服务架构的设计模式(转)
    Linux Shell 命令
    Condition的await-signal流程详解(转)
  • 原文地址:https://www.cnblogs.com/cly-none/p/9562032.html
Copyright © 2011-2022 走看看