[机房测试]matrix

求出满足以下条件的 n*m 的 01 矩阵个数:
(1)第 i 行第 1~li 列恰好有 1 个 1。
(2)第 i 行第 ri~m 列恰好有 1 个 1。
(3)每列至多有 1 个 1

这题还是很有趣的,模拟一下样例就想出dp方法了
最难想到的是要按列来枚举……
详细见代码注释吧

代码:

#include<bits/stdc++.h>
#define ll long long
#define mod 998244353
#define N 3005
#define pos1 (rsum[i]-j+1)
#define pos2 (i-j-k)
using namespace std;

int n,m;
ll f[N][N],delta1,delta2;//f[i][j]表示前i列中有j列的右区间放了1 
ll lsum[N],rsum[N];//1~l和r~m已经放了多少个1 

struct Limit
{
    ll l,r;
}a[N];

template<class T>inline void read(T &res)
{
    char c;T flag=1;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

ll Mod(ll x){return x%mod;}

int main()
{
    freopen("matrix.in","r",stdin);
    freopen("matrix.out","w",stdout);
    read(n);read(m);
    for(register int i=1;i<=n;++i)
    {
        read(a[i].l);
        read(a[i].r);
        lsum[a[i].l]++;
        rsum[a[i].r]++;
    }
    f[0][0]=1;
    for(register int i=1;i<=m;++i)//枚举前 i 列 
    {
        f[i][0]=f[i-1][0];
        lsum[i]=lsum[i]+lsum[i-1];
        rsum[i]=rsum[i]+rsum[i-1];
        for(register int j=1;j<=i;++j)
        {
            delta1=Mod(f[i-1][j]);//右边不放1,直接转移 
            delta2=Mod(f[i-1][j-1]*pos1);//右边放1,方案数乘上剩余的位置 
            f[i][j]=Mod(delta1+delta2);
        }
        for(register int j=lsum[i-1];j<=lsum[i]-1;++j)//枚举左边还差多少个1 
        {
            for(register int k=0;k<=i;++k)//共有k个右区间放了1 
                f[i][k]=Mod(f[i][k]*pos2);//贡献=方案数*剩余位置 
        }
    }
    printf("%lld\n",f[m][n]);
    return 0;
}
/*
5 200
60 170
50 120
80 90
70 110
80 100
*/

转载于:https://www.cnblogs.com/tqr06/p/11599970.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值