AcWing 306. 杰拉尔德和巨型象棋 计数类DP

参考秦大佬的题解: https://www.acwing.com/solution/AcWing/content/1730/


//通过容斥原理
//那么F[i]表示为从左上角走到第i个黑色格子,而且途中不经过其他黑色格子的方案数 
//终点作为第k+1个黑格子

//F[i]=(1,1)到(xi,xj)的总方案数-前(i-1)黑格方案数*黑格到(xi,yi)的方案数 
//其中, (1,1)到(xi,xj)的总方案数为C(xi-1+yi-1,xi-1)
 
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int N=200020;
const int mod=1e9+7;
int n,m,k;
int fact[N], infact[N];
pair<int,int>date[N]; 
int f[N];
typedef long long LL;
int qmi(int a,int k,int p)
{
    int res=1%p;
    while(k)
    {
        if(k&1) 
			res=res*a%p;
        a=a*a%p;
        k >>= 1;
    }
    return res;
}
int C(int a,int b)
{
	return fact[a]*infact[b]%mod*infact[a-b]%mod;
}
signed main()
{
	cin>>n>>m>>k;
    for(int i=1;i<=k;i++)
    	cin>>date[i].first>>date[i].second;
    fact[0]=infact[0]=1;
    for(int i=1;i<N;i++)
    {
        fact[i]=(LL)fact[i-1]*i%mod;
        infact[i]=(LL)infact[i-1]*qmi(i,mod-2,mod)%mod;
    }
    sort(date+1,date+1+k);
    date[k+1]=make_pair(n,m);
    f[0]=1;
    
	for(int i=1;i<=k+1;i++)
	{
		int x=date[i].first,y=date[i].second;
		f[i]=C(x+y-2,x-1);
		for(int j=1;j<i;j++)
		{
			int a=date[j].first,b=date[j].second;
			if(a<=x && b<=y)
				f[i]=(f[i]-f[j]*(long long)C(x-a+y-b,x-a))%mod;
		}
	}
	cout<<(f[k+1]+mod)%mod<<endl;
	return 0;
} 

原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12601042.html