2018.11.07 codeforces559C. Gerald and Giant Chess(dp+组合数学)

时间:2021-08-19 08:28:20

传送门

令f[i]f[i]f[i]表示对于第iii个棋子,从(1,1)(1,1)(1,1)出发到它不经过其它棋子的方案数。

于是我们假设(h,w)(h,w)(h,w)有一个棋子,求出它的fff值就可以了。

然后考虑容斥转移fff数组。

根据定义,我们求出从(1,1)(1,1)(1,1)出发到它的总方案数,再减去经过了其它棋子的方案数。

然后再考虑如何才会补充不漏。

发现从之前每一个fff转移过来就行了。

fi=(xi+yi−2xi−1)−∑fj∗(xi−yi+xj−yjxi−xj)f_i=\binom{x_i+y_i-2}{x_i-1}-\sum f_j*\binom{x_i-y_i+x_j-y_j}{x_i-x_j}fi​=(xi​−1xi​+yi​−2​)−∑fj​∗(xi​−xj​xi​−yi​+xj​−yj​​)

代码:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
typedef long long ll;
const int N=2e3+5,M=1e5+5,mod=1e9+7;
int h,w,n,f[N],fac[M+M],ifac[M+M];
struct Node{
	int x,y;
	friend inline bool operator<(const Node&a,const Node&b){return a.x==b.x?a.y<b.y:a.x<b.x;}
}p[N];
inline int C(const int&n,const int&m){return (ll)fac[n]*ifac[m]%mod*ifac[n-m]%mod;}
int main(){
	h=read(),w=read(),n=read(),fac[0]=fac[1]=ifac[0]=ifac[1]=1;
	for(int i=2;i<=h+w;++i)fac[i]=(ll)fac[i-1]*i%mod;
	for(int i=2;i<=h+w;++i)ifac[i]=(ll)ifac[mod%i]*(mod-mod/i)%mod;
	for(int i=2;i<=h+w;++i)ifac[i]=(ll)ifac[i]*ifac[i-1]%mod;
	for(int i=1;i<=n;++i)p[i].x=read(),p[i].y=read();
	p[++n]=(Node){h,w},sort(p+1,p+n+1);
	for(int i=1;i<=n;++i){
		f[i]=C(p[i].x+p[i].y-2,p[i].x-1);
		for(int j=1;j<i;++j){
			if(p[j].y>p[i].y)continue;
			f[i]=f[i]-(ll)f[j]*C(p[i].x+p[i].y-p[j].x-p[j].y,p[i].x-p[j].x)%mod;
			if(f[i]<0)f[i]+=mod;
		}
	}
	cout<<f[n];
	return 0;
}