4767: 两双手

来源:互联网 发布:微博上最恶心的公知 编辑:程序博客网 时间:2024/05/01 07:36

4767: 两双手

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 581  Solved: 167
[Submit][Status][Discuss]

Description

老W是个棋艺高超的棋手,他最喜欢的棋子是马,更具体地,他更加喜欢马所行走的方式。老W下棋时觉得无聊,便
决定加强马所行走的方式,更具体地,他有两双手,其中一双手能让马从(u,v)移动到(u+Ax,v+Ay)而另一双手能让
马从(u,v)移动到(u+Bx,v+By)。小W看见老W的下棋方式,觉得非常有趣,他开始思考一个问题:假设棋盘是个无限
大的二维平面,一开始马在原点(0,0)上,若用老W的两种方式进行移动,他有多少种不同的移动方法到达点(Ex,Ey
)呢?两种移动方法不同当且仅当移动步数不同或某一步所到达的点不同。老W听了这个问题,觉得还不够有趣,他
在平面上又设立了n个禁止点,表示马不能走到这些点上,现在他们想知道,这种情况下马有多少种不同的移动方
法呢?答案数可能很大,你只要告诉他们答案模(10^9+7)的值就行。

Input

第一行三个整数Ex,Ey,n分别表示马的目标点坐标与禁止点数目。
第二行四个整数Ax,Ay,Bx,By分别表示两种单步移动的方法,保证Ax*By-Ay*Bx≠0
接下来n行每行两个整数Sxi,Syi,表示一个禁止点。
|Ax|,|Ay|,|Bx|,|By| <= 500, 0 <= n,Ex,Ey <= 500

Output

仅一行一个整数,表示所求的答案。

Sample Input

4 4 1
0 1 1 0
2 3

Sample Output

40

HINT

Source

[Submit][Status][Discuss]



显然,能到达的每个点,到达时走到的步数是唯一确定的

相当于解一个二元一次方程组

那么按照起点出发经过的步数,将所有被禁止的点排序

定义f[i]:起点走到第i个点,中间不经过其它点的方案数

那么,f[i] = ways(1,i) - ∑f[k]*ways(k,i) (k = 2~i-1)

其中ways(x,y)即从点x走到点y的方案数,用组合数算一下就行了

预处理阶乘和逆元,O(n^2)

注意本题阶乘和逆元范围略大。。。。于是RE了好久

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<algorithm>#include<cmath>#include<stack>using namespace std; const int N = 505;const int M = 5E5 + 50;typedef long long LL;const LL mo = 1000000007; struct Point{    int x,y,step; Point(){}    Point(int x,int y,int step): x(x),y(y),step(step){}    bool operator < (const Point &B) const {return step < B.step;}}p[N]; int n,Ex,Ey,tot,dx[2],dy[2],f[N],Fac[M],Inv[M]; inline int Mul(const LL &x,const LL &y) {return x * y % mo;}inline int Add(const int &x,const int &y) {return x + y < mo ? x + y : x + y - mo;}inline int Dec(const int &x,const int &y) {return x - y >= 0 ? x - y : x - y + mo;}inline int C(const int &N,const int &M) {return Mul(Fac[N],Mul(Inv[M],Inv[N - M]));} int ksm(int x,int y){    int ret = 1;    for (; y; y >>= 1)    {        if (y & 1) ret = Mul(ret,x);        x = Mul(x,x);    }    return ret;} inline int Ways(int x,int y){    int A = x * dy[1] - dx[1] * y;    int B = dx[0] * dy[1] - dx[1] * dy[0];    if (A % B != 0) return 0;    int a = A / B,b;    if (dx[1] != 0)    {        b = x - dx[0] * a;        if (b % dx[1] != 0) return 0;        b /= dx[1];    }    else    {        b = y - dy[0] * a;        if (b % dy[1] != 0) return 0;        b /= dy[1];    }    return (a < 0 || b < 0) ? 0 : C(a + b,a);} inline int Calc(int x,int y){    int A = x * dy[1] - dx[1] * y;    int B = dx[0] * dy[1] - dx[1] * dy[0];    if (A % B != 0) return -1;    int a = A / B,b;    if (dx[1] != 0)    {        b = x - dx[0] * a;        if (b % dx[1] != 0) return -1;        b /= dx[1];    }    else    {        b = y - dy[0] * a;        if (b % dy[1] != 0) return -1;        b /= dy[1];    }    return (a < 0 || b < 0) ? -1 : a + b;} int main(){    #ifdef DMC        freopen("DMC.txt","r",stdin);    #endif         Fac[0] = 1; for (int i = 1; i < M; i++) Fac[i] = Mul(Fac[i - 1],i);    Inv[M - 1] = ksm(Fac[M - 1],mo - 2); for (int i = M - 2; i >= 0; i--) Inv[i] = Mul(Inv[i + 1],i + 1);    cin >> Ex >> Ey >> n >> dx[0] >> dy[0] >> dx[1] >> dy[1];    int End = Calc(Ex,Ey);    if (End == -1) {cout << 0 << endl; return 0;}    p[++tot] = Point(0,0,0); p[++tot] = Point(Ex,Ey,End);    for (int i = 1; i <= n; i++)    {        int x,y; scanf("%d%d",&x,&y);        int now = Calc(x,y);        if (now == -1 || now >= End) continue;        p[++tot] = Point(x,y,now);    }    sort(p + 1,p + tot + 1); f[1] = 1;    for (int i = 2; i <= tot; i++)    {        f[i] = Ways(p[i].x,p[i].y);        for (int j = 2; j < i; j++)            f[i] = Dec(f[i],Mul(f[j],Ways(p[i].x - p[j].x,p[i].y - p[j].y)));    }    cout << f[tot] << endl;    return 0;}

0 0
原创粉丝点击