Codeforces559 C.Gerald and Giant Chess(dp+组合数学+容斥)

博客主要讨论了一种计算从点(1,1)到给定黑点路径的算法,考虑了路径不经过其他黑点的情况,并使用了组合数学中的组合公式。通过排序黑点并应用容斥原理,实现了O(n^2)的时间复杂度计算方案数。最后给出了C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

在这里插入图片描述
答案对1e9+7取模。

数据范围:h,w<=1e5,n<=2e3

解法:

在这里插入图片描述
对黑点排序。
令d[i]表示从(1,1)到达第i个黑点(x,y),且不经过其他黑点的方案数,
如果(1,1)到(x,y)矩形内没有其他黑点,那么方案数为C(x-1+y-1,x-1)=C(x+y-2,x-1),
如果有其他黑点,考虑容斥,需要减掉(1,1)到(x,y)矩形内的黑点j到达当前点i的方案数
那么d[i]-=d[j]*C(xi-xj+yi-yj,xi-xj)。

O(n2)即可计算出结果。

code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define PI pair<int,int>
const int maxm=2e5+5;
const int mod=1e9+7;
int fac[maxm],inv[maxm];
struct Node{
    int x,y;
}e[maxm];
int d[maxm];//d[i]表示(1,1)到达第i个黑点,不经过任何其他黑点的方案数.
int n,m,k;
int ppow(int a,int b,int mod){
    int ans=1%mod;a%=mod;
    while(b){
        if(b&1)ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
void init(){
    fac[0]=1;
    for(int i=1;i<maxm;i++)fac[i]=fac[i-1]*i%mod;
    inv[maxm-1]=ppow(fac[maxm-1],mod-2,mod);
    for(int i=maxm-2;i>=0;i--)inv[i]=(i+1)*inv[i+1]%mod;
}
int C(int n,int m){
    if(m<0||m>n)return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
signed main(){
    init();
    cin>>n>>m>>k;
    for(int i=1;i<=k;i++){
        cin>>e[i].x>>e[i].y;
    }
    e[++k]={n,m};//将(n,m)看作第k+1个黑点,那么d[k+1]就是答案
    sort(e+1,e+1+k,[](Node a,Node b)->bool{
            if(a.x==b.x)return a.y<b.y;
            return a.x<b.x;
        });
    for(int i=1;i<=k;i++){
        d[i]=C(e[i].x+e[i].y-2,e[i].x-1);
        for(int j=1;j<i;j++){
            if(e[j].x<=e[i].x&&e[j].y<=e[i].y){
                d[i]-=d[j]*C(e[i].x-e[j].x+e[i].y-e[j].y,e[i].x-e[j].x)%mod;
                d[i]%=mod;
            }
        }
    }
    cout<<(d[k]+mod)%mod<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值