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 }

 

posted @ 2017-10-06 11:43  Nawox  阅读(247)  评论(0编辑  收藏  举报