Gerald and Giant Chess(计数dp+组合数学)

codeforces 559C Gerald and Giant Chess

题目大意:就是说给你一个h*w的矩阵,让你从(1,1)走到(h,w)问你右多少种走法

计算左上到右下的方法如果不考虑黑点的话,sum=C(h+w)(h)

因为存在黑点i(x,y),所以用所以计算从左上到黑点的方法有sum[i] = C(x+y)(x),其中如果在黑点的左上还有黑点j(u,v),那么应该减去sum[j]*C(x-u+y-v)(y-u),去掉所有在左上的黑点的影响就可以得到由左上到第i点的真正的方法数

从左上的第一个黑点,一直计算到右下(h,w)

注意一定要减去sum[j]

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e6+100;
const int mod=1e9+7;
ll f[maxn];
ll sum[maxn];
int h,w,n;
struct node{
    int x,y;
}a[maxn];
bool cmp(node a,node b){
    if(a.x==b.x){
        return a.y<b.y;
    }
    else{
        return a.x<b.x;
    }
}
ll qpow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1){
            ans=(ans*a)%mod;
        }
        a=(a*a)%mod;
        b/=2;
    }
    return ans%mod;
}
void inint(){
    f[1]=1;
    for(int i=2;i<=2e5+1;i++){
        f[i]=(f[i-1]*i)%mod;
    }
}
ll C(ll n,ll m){
    if(m==0||n==m){//注意调试了半天 
        return 1ll;
    } 
    ll ans=(((f[n]%mod*qpow(f[m],mod-2))%mod*qpow(f[n-m],mod-2))%mod)%mod;
    return ans%mod;
}
int main(){
    inint(); 
    cin>>h>>w>>n; 
    for(int i=0;i<n;i++){
        cin>>a[i].x>>a[i].y;
    }
    a[n].x=h,a[n++].y=w; 
    sort(a,a+n,cmp);
    int x1,y1,x2,y2; 
    for(int i=0;i<n;i++){//找的是起点 
        x1=a[i].x-1;y1=a[i].y-1;//为什么要减1呢,就是从1,1到2,3要向下1步,向右2个,所以要减1 
        sum[i]=C(x1+y1,x1)%mod;
        for(int j=0; j<i ;j++){
            if(a[j].x<=a[i].x && a[j].y<=a[i].y){
                x2=x1-a[j].x+1,y2=y1-a[j].y+1;
                ll p=C(x2+y2,x2)*sum[j]%mod;
                sum[i]=(sum[i]-p+mod)%mod;
            }
        }
    }
    cout<<sum[n-1]<<endl;
}
原文地址:https://www.cnblogs.com/lipu123/p/14027727.html