zoukankan      html  css  js  c++  java
  • bzoj4767两双手 容斥+组合

    4767: 两双手

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 684  Solved: 208
    [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

    组合+容斥
    可以发现两种方法走的步数是一定的
    因为 AX*x+BX*y=ex AY*x+BY*y=ey唯一解
    特判能不能走到此点,并且把坐标化成二元一次方程组的解(x,y)
    那么ans=总方案-路上经过禁止点的方案

    算路径方案用组合数
    (0,0)一次向上或右走一单位,走到(n,m)的方案为C(n+m,m)

    再考虑路上经过禁止点的方案
    对于每个禁止点,可以算出到达它的方案,再用容斥减去之前已经经过禁止点的方案
    对于禁止点i,如果禁止点j可以到达i,那么到达i的方案要减去到达j再到i的方案
    由于坐标化简后相当于只向右上走,所以按坐标排序,只有排在它之前的点可能到达它

    /*
    代码wa了没调出来。
    */
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #define ll long long
    #define N 505
    #define mod 1000000007
    using namespace std;
    int ex,ey,ax,ay,bx,by,cnt,n,m,num,fac[1005*1005],f[N];
    struct node{int x,y;}p[N];
    bool check(int x,int y,int &a,int &b){
        int t1=x*by-y*bx,t2=ax*by-ay*bx;
        if(t1%t2)return 0;
        a=t1/t2;
        t1=x*ay-y*ax;t2=-t2;
        if(t1%t2)return 0;
        b=t1/t2;return 1;
    }
    void pre(){
        fac[0]=1;
        for(int i=1;i<=1e6;i++)fac[i]=(1ll*fac[i-1]*i)%mod;
    }
    int quick(int a,int b){
        int c=1;
        while(b){
            if(b&1)c=(1ll*c*a)%mod;
            a=(1ll*a*a)%mod;b>>=1;
        }
        return c;
    }
    int C(int x,int y){
        int ans=fac[x];
        int d1=quick(fac[y],mod-2);
        int d2=quick(fac[x-y],mod-2);
        ans=(1ll*ans*d1)%mod;
        ans=(1ll*ans*d2)%mod;
        return ans;
    }
    int calc(int x,int y){
        if(x<0||y<0)return 0;
        return C(x+y,y);
    }
    bool cmp(node a,node b){return a.x==b.x?a.y<b.y:a.x<b.x;}
    int main(){
    #ifdef wsy
        freopen("data.in","r",stdin);
    #else
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
    #endif
        int A,B;
        scanf("%d%d%d",&ex,&ey,&num);
        scanf("%d%d%d%d",&ax,&ay,&bx,&by);
        if(!check(ex,ey,n,m)){puts("0");return 0;}
        for(int i=1;i<=num;i++){
            int a,b;scanf("%d%d",&a,&b);
            if(check(a,b,A,B)&&A>=1&&A<=n&&B>=1&&B<=m)
            p[++cnt].x=A;p[cnt].y=B;
        }
        pre();
        p[++cnt].x=n;p[cnt].y=m;
        sort(p+1,p+1+cnt,cmp);
        for(int i=1;i<=cnt;i++){
            f[i]=calc(p[i].x,p[i].y);
            for(int j=1;j<i;j++)
            f[i]=(f[i]-(ll)f[j]*calc(p[i].x-p[j].x,p[i].y-p[j].y))%mod;
        }
        f[cnt]<0?f[cnt]+=mod:1;
        cout<<f[cnt];
        return 0;
    }
  • 相关阅读:
    node-webkit 笔记
    CEF 相关资料
    输出重定向
    FindProcDLL::FindProc 和 KillProcDLL::KillProc,必须使用WPF x86编译出来的程序
    wpf xaml inlines
    Gradle 笔记
    Android手机的 storage
    SpringMVC 工作原理详解
    SpringMVC 面试题
    18、多线程 (线程安全、线程同步、等待唤醒机制、单例设计模式)
  • 原文地址:https://www.cnblogs.com/wsy01/p/8022365.html
Copyright © 2011-2022 走看看