zoukankan      html  css  js  c++  java
  • 【xsy2425】容器 dp

    题目大意:有$n$个人,区间大小为$m$,每个人必须覆盖一段区间$[l_i,r_i]$,问你存在多少种不同的覆盖方案,使得区间上每个位置被覆盖的次数不超过$t$。

    两种方案被定义为不同当且仅当存在第i个人覆盖的区间不同。

    求方案数,对一个质数取模。

    数据范围:$n,m,t≤40$

    我们考虑dp。

    设$f[i][j][k]$表示区间的前i个位置,总共有$j$个人参与了覆盖,且有$k$个人同时覆盖了位置$i$,位置$i+1$的方案数。

    我们考虑枚举$J$和$K$,需要保证$j<J$

    那么我们显然可以用f[i][j][k]的值去更新$f[i+1][J][K]$的值。

    从$f[i][j][k]$到$f[i+1][J][K]$,用的人数多了$J-j$个,我们要从$n-j$个人中选出$J-j$个人去增加总人数,方案数显然为$inom {n-j}{J-j}$。

    然后,我们还要保证有$K$个人可以覆盖到$i+2$,而这$K$个人显然只能从$k+(J-j)$个人中选出,方案数显然为$inom {k+(J-j)}{K}$。

    那么转移方程大概长这样:

    $f[i+1][J][K]+=f[i][j][k] imes inom{n-j}{J-j} imes inom{J-j+k}{K}$

    复杂度为$O(nk^4)$

     1 #include<bits/stdc++.h>
     2 #define L long long
     3 #define M 55
     4 #define MOD 1011110011
     5 using namespace std;
     6  
     7 L n,m,t,c[M][M]={0},f[M][M][M]={0};
     8  
     9 int main(){
    10     for(int i=0;i<M;i++){
    11         c[i][0]=1;
    12         for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
    13     }
    14     cin>>n>>m>>t;
    15     f[0][0][0]=1;
    16     for(int i=0;i<n;i++)
    17     for(int j=0;j<=m;j++)
    18     for(int k=0;k<=j;k++)
    19     if(f[i][j][k]){
    20         for(int J=j;J<=m;J++)
    21         for(int K=0;K<=J;K++){
    22             int cnt=J-j+k;
    23             if(cnt>t) continue;
    24             (f[i+1][J][K]+=f[i][j][k]*c[m-j][J-j]%MOD*c[cnt][K]%MOD)%=MOD;
    25         }
    26     }
    27     cout<<f[n][m][0]<<endl;
    28 }
  • 相关阅读:
    H: Dave的组合数组(二分法)
    G: Dave的时空迷阵(next数组)
    计蒜客 X的平方根(二分法)
    最短路径四种方法
    POJ 2001 Shortest Prefixes(字典树活用)
    HDU 1671 Phone List (qsort字符串排序与strncmp的使用 /字典树)
    快速排序原理
    抓捕盗窃犯
    Hash函数
    Monkey King(左偏树 可并堆)
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10626488.html
Copyright © 2011-2022 走看看