zoukankan      html  css  js  c++  java
  • matrix

     这个题是一道dp

      虽然是一个二维的矩阵,但是状态转移方程表示的却是有一维

     f[i][j] 表示到第i列,有j行的右区间中有一个1

     考虑如何转移,枚举每一列,因为j表示的是有区间有多少已经有1,那么左区间是不用一开始就考虑的,因为只考虑左区间的话,那么肯定是先往小的里放,所以我们可以在每一次扫到一个左区间的右端点后,在统计右端点以内有多少个空着的列,然后放入这些区间,

    对于怎么统计这些空区间,可以用两个前缀和lsum[],rsum[],分别记录到i为止,有几个左区间的右端点和右区间的左端点,那么当枚举到i的时候,第i列显然有lsum[i]-lsum[i-1]个右端点 ,但是占据1~i这些列的还有j个右区间,所以可选的空位置有(i-lsum[i-1]-j)个,那么对答案的贡献就是A(i-lsum[i-1]-j,lsum[i]-lsum[i-1]);

    然后考虑有区间的转移,当从i转移到i+1时,那么一定有rsum[i+1]个右区间可以在i+1的位置上放上1,但是之前可能一应放过了,所以在第i+1列放1的选择为srum[i+1]-j; 

    这样转移下去就行了

    CODE:

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cstdlib>
     5 #include <iostream>
     6 #include <algorithm>
     7 # define maxn 3010
     8 # define mod 998244353
     9 using namespace std;
    10 typedef long long LL;
    11 int n,m;
    12 int L[maxn],R[maxn];
    13 int cun[maxn];
    14 LL sl[maxn],sr[maxn];
    15 LL f[maxn][maxn];
    16 LL jc[maxn],njc[maxn];
    17 LL ksm(LL a,LL b){
    18     LL ans=1;
    19     while(b){
    20         if(b&1) ans*=a,ans%=mod;
    21         b=b>>1; a*=a; a%=mod;
    22     }
    23     return ans;
    24 }
    25 void beg(){
    26     memset(cun,0,sizeof(cun));
    27     for(int i=1;i<=n;i++) cun[L[i]]++;
    28     for(int i=1;i<=m;i++) sl[i]=sl[i-1]+cun[i];
    29     memset(cun,0,sizeof(cun));
    30     for(int i=1;i<=n;i++) cun[R[i]]++;
    31     for(int i=1;i<=m;i++) sr[i]=sr[i-1]+cun[i];
    32     jc[0]=1; njc[0]=1;
    33     for(int i=1;i<=max(n,m);i++) jc[i]=jc[i-1]*i,jc[i]%=mod;
    34     for(int i=1;i<=max(n,m);i++) njc[i]=ksm(jc[i],mod-2);
    35 }
    36 LL A(int n,int m){
    37     if(n<0 || m<0) return 0;
    38     if(m>n) return 0;
    39     return jc[n]*njc[n-m]%mod;
    40 }
    41 void DP(){
    42     f[1][0]=1;
    43     for(int i=1;i<m;i++){
    44         for(int j=0;j<=n;j++){
    45             f[i+1][j]+=f[i][j];
    46             if(sr[i+1]-j>0){
    47                 f[i+1][j+1]+=f[i][j]*(sr[i+1]-j);
    48                 f[i+1][j+1]%=mod;
    49             }
    50         }
    51         for(int j=0;j<=n;j++){
    52             f[i+1][j]=f[i+1][j]*A(i+1-sl[i]-j,sl[i+1]-sl[i]);
    53             f[i+1][j]%=mod;
    54         }
    55     }
    56     cout<<f[m][n]<<endl;
    57 }
    58 int main(){
    59     // freopen("b.in","r",stdin);
    60     scanf("%d%d",&n,&m);
    61     for(int i=1;i<=n;i++) scanf("%d%d",&L[i],&R[i]);
    62     beg();
    63     DP();
    64 }
  • 相关阅读:
    java实现调用打印机代码
    java合并PDF文件
    关于如何把项目做得更好的一次思考
    web语义化之SEO和ARIA
    快速理解web语义化
    使用HTML5地理位置定位到城市的方法及注意事项
    Plupload上传插件简单整理
    两列布局——左侧宽度固定,右侧宽度自适应的两种方法
    Java并发编程之线程基础
    Spring Boot学习之YAML文件配置
  • 原文地址:https://www.cnblogs.com/FOXYY/p/7631308.html
Copyright © 2011-2022 走看看