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;  
} 

猜你喜欢

转载自www.cnblogs.com/sssy/p/9762975.html