bzoj 4767: 两双手 组合 容斥

题目链接

bzoj4767: 两双手

题解

不共线向量构成一组基底
对于每个点\((X,Y)\)构成的向量拆分
也就是对于方程组
$Ax * x + Bx * y = X \( \)Ay * x + By * y = Y\( \)x,y\(不能为负问题转化为NE lattice path \)f(i)\(表示从0到i点不经过障碍的方案数 枚举第一个碰到的障碍点 \)f(i) = cnt(0,i) - \sum_j dp[j] cnt(j,i)$
\(cnt(x,y)\)为从点x到y的方案数

代码


#include<cstdio> 
#include<algorithm> 
#include<cstring> 
#define gc getchar() 
#define pc putchar
inline int read() { 
	int x = 0,f = 1; 
	char c = gc; 
	while(c < '0' || c > '9') {if(c == '-') f = -1 ; c = gc; }
	while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = gc; 
	return x * f; 
} 
void print(int x) { 
	if(x >= 10) print(x / 10); 
	pc(x % 10 + '0'); 
} 
#define int long long
const int maxn = 507; 
const int M = 500000; 
const int mod = 1e9 + 7; 
int Ex,Ey,n; 
int Ax,Ay,Bx,By; 
int f[maxn]; 
struct Node {
int x,y; 
	bool operator < (const Node a) const {
		return x == a.x ? y < a.y : x < a.x; 
	} 
} p[maxn]; 
int fac[M + 7],inv[M + 7]; 
inline int fstpow(int x,int k) { 
	int ret =  1; 
	for(;k;k >>= 1,x = 1ll * x * x % mod) 
		 if(k & 1) ret = 1ll * ret * x % mod; 
	return ret; 
} 
inline void calc(int &x,int &y)  { 
	int a1 = x * By - y * Bx,a2 = Ax * By - Ay * Bx; 
	int b1 = x * Ay - Ax * y,b2 = Bx * Ay - Ax * By; 
	if(!a2 || !b2) {x = y = -1;return; } 
	if((a1 % a2) || (b1 % b2)) {x = y = -1;return; } 
	x = a1 / a2,y = b1 / b2; 
} 
inline int C(int x,int y){ 
	if(x < y) return 0; 
	return 1ll * fac[x] * inv[y] % mod * inv[x - y] % mod; 
} 
main() { 
	fac[0] = fac[1] = 1; 
	
	for(int i = 1;i <= M;++ i) fac[i] = 1ll * fac[i - 1] * i % mod; 
	inv[0] = 1; 
	inv[M] = fstpow(fac[M],mod - 2); 
	
	for(int i = M - 1;i >= 1;-- i) inv[i] = 1ll * inv[i + 1] * (i + 1) % mod; 
	
	Ex = read(),Ey = read(),n = read(); 
	Ax = read(),Ay = read(),Bx = read(),By = read(); 
	
	calc(Ex,Ey); 
	
	for(int i = 1;i <= n;++ i) { 
		 p[i].x = read(),p[i].y = read(); 
		calc(p[i].x,p[i].y); 
		if(p[i].x < 0 || p[i].y < 0 || p[i].x > Ex || p[i].y > Ey) n --,i --; 
	} 
	p[0].x = p[0].y = 0; 
	p[++ n].x = Ex,p[n].y = Ey; 
	
	std::sort(p + 1,p + n + 1); 
	
	for(int i = 1;i <= n;++ i) { 
		f[i] = C(p[i].x + p[i].y,p[i].x); 
		if(f[i] == 0) continue; 
		for(int j = 1;j < i;++ j) { 
			f[i] -= (1ll * f[j] * C(p[i].x - p[j].x + p[i].y - p[j].y,p[i].x - p[j].x)) % mod; 
			f[i] %= mod; 
			f[i] += mod ;
			f[i] %= mod; 
		} 
	} 
	print(f[n]); 
	return 0;  
} 
posted @ 2018-10-09 21:22  zzzzx  阅读(163)  评论(0编辑  收藏  举报