FJNU Yehan’s hole 组合数逆元+容斥

Yehan’s hole

Description

Yehan is a angry grumpy rabbit, who likes jumping into the hole. This day,Yehan jumps again in the pit at home. Each time, he should jump from the hole at the coordinate (1,1) to (n,m), and he has to jump as the way : he can only jump (x, y) to (x+1, y) or (x, y+1). At his home, some holes are filled with water, he couldn’t jump in them. Yehan wants to know how many different way he could jump. If the paths of two ways are different, Yehan considers they are different.

Input

Multiple test dataThe first line of input contains two numbers n, m (2 <= n, m < 1e5)The second line of input contains a number q, the number of holes (q <= 15)The following q lines, the i-th line contains two numbers xi, yi (1 < x1 < x2 < x3 <……< xq < n) (1 < y1 < y2 < y3 < …… < yq < m)

Output

Output contains one line, the number of ways, because the result is too large, you should mod 1000000007

Sample Input 1 

3 3
1
2 2

Sample Output 1

2

题意:从左上角(1,1)走到右下角(n,m),n*m的图中有一些格点是洞,不能走,且只能往右和向下走,问方案数。

题解:如果没有洞,那么我们只要往下或往右走,那么另外一边就可以确定了,那么总的方案数就是C(n-1,n+m-2);

有洞的情况,我们就可以用容斥定理,总方案数减去经过一个洞的情况,加上经过两个洞的情况,减去经过三个洞的情况。。。

注意最后答案要加上模数后再取模,因为dfs容斥过程中答案有可能出现负数。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#include<vector> 
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mem(a,b) memset(a,b,sizeof(a));
#define lowbit(x)  x&-x;  
typedef long long ll;
const int mod = 1e9 + 7;
const int mx = 1e5 + 5;
struct node{
	int x,y;
}hole[mx];
int n,m,h;
ll inv[2*mx+20];
ll fac[2*mx+20];
ll ans; 
ll pow_inv(ll a,ll b){
	ll res = 1;
	while(b){
		if(b&1) res = (res*a)%mod;
		a = (a*a)%mod;
		b >>= 1;
	}
	return res;
}
void Inv(){ //阶乘逆元 
	fac[0] = 1;
	for(int i = 1; i <= 200000; i++) //阶乘打表 
		fac[i] = (fac[i-1]*i)%mod;
	inv[200000] = pow_inv(fac[200000],mod-2); //最大阶乘逆元 
	for(int i = 200000-1; i >= 0; i--)
		inv[i] = (inv[i+1]*(i+1))%mod; //递推阶乘逆元
}
ll C(ll b,ll a){
	return fac[a]*inv[b]%mod*inv[a-b]%mod;
} 
void dfs(int cur,int pre,ll temp,int s){ //当前洞,前一个洞,种类数,取了几个洞(容斥) 
	ll tmp1,tmp2;
	s++;
	tmp1 = temp*C(hole[cur].x-hole[pre].x,hole[cur].x+hole[cur].y-hole[pre].x-hole[pre].y)%mod; //前一个洞到当前洞的种类数 
	tmp2 = tmp1*C(n-hole[cur].x,n+m-hole[cur].x-hole[cur].y)%mod;   //当前洞到终点的种类数 
	if(s&1) ans = (ans + tmp2)%mod; //注意取模
	else ans = (ans - tmp2)%mod;
	for(int i = cur+1; i <= h; i++){
		dfs(i,cur,tmp1,s);
	} 
}
int main(){
	Inv();
	while(~scanf("%d%d",&n,&m)){
		scanf("%d",&h);
		hole[0].x = 1,hole[0].y = 1;
		rep(i,1,h){
			scanf("%d%d",&hole[i].x,&hole[i].y);
		}
		ans = 0;
		rep(i,1,h){
			dfs(i,0,1,0);
		}
		printf("%lld\n",((C(n-1,n+m-2)-ans)%mod+mod)%mod);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/pall_scall/article/details/82393060