bzoj4767

首先一个向量可以被两个向量唯一表示 然后就转化为有障碍点的网格图路径计数
这应该是个经典的容斥模型 果然是NOIP模拟赛啊
如果不考虑障碍 那么答案是path(s,t)=Cmn+m
然后我们考虑容斥 枚举路径上碰到的第一个障碍点v
Ans=Cmn+m−fv∗path(v,t)

其中fv表示从起点s出发不经过其他障碍点到达v的路径数 path(v,t) 表示从v到t不考虑障碍的路径数 这显然也是个组合数
fv怎么求 从头开始DP就好了
inv[]表示逆元乘积线性求逆元即证明

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
typedef pair<int,int> abcd;
typedef long long ll;
const int mo=1e9+7;
const int maxn=1000002;
ll fac[maxn],inv[maxn];
int n,m,tot,f[502],ax,ay,bx,by,ex,ey;
abcd pt[maxn];
inline void read(int &x){
    char ch=getchar();x=0;int f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    x*=f;
}
inline void init(int n=500000){
    fac[0]=1;for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mo;
    inv[1]=1;for(int i=2;i<=n;i++)inv[i]=(ll)(mo-mo/i)*inv[mo%i]%mo;
    inv[0]=1;for(int i=1;i<=n;i++)inv[i]=inv[i]*inv[i-1]%mo;
}
inline ll C(int n,int m){return fac[n]*inv[m]%mo*inv[n-m]%mo;}
inline ll path(int j,int i){
    int dx=pt[i].first-pt[j].first,dy=pt[i].second-pt[j].second;
    if(dx<0 || dy<0)return 0;
    return C(dx+dy,dx);
}
inline bool calc(int x,int y,int &A,int &B){
    int s=x*by-y*bx,t=ax*by-ay*bx;
    if(s%t)return 0;else A=s/t;
    s=x*ay-y*ax,t=bx*ay-by*ax;
    if(s%t)return 0;else B=s/t;
    return 1;
}
 
int main(){
  int A,B,x,y;init();
  read(ex);read(ey);read(tot);
  read(ax);read(ay);read(bx);read(by);
  if(!(calc(ex,ey,A,B) || A<0 || B<0))return printf("0\n"),0;else n=A,m=B;
  int tmp=tot;tot=0;
  for(int i=1;i<=tmp;i++){
    read(x);read(y);
    if(calc(x,y,A,B) && A>=0 && B>=0 && A<=n && B<=m)pt[++tot]=abcd(A,B);
  }
  pt[++tot]=abcd(n,m);
  sort(pt+1,pt+tot+1);
  f[0]=1;
  for (int i=1;i<=tot;i++){
    f[i]=path(0,i);
    for (int j=1;j<i;j++)
      f[i]=(f[i]+mo-(ll)f[j]*path(j,i)%mo)%mo;
  }
  printf("%d\n",f[tot]);
  return 0;
}
posted @ 2018-07-06 21:11  lnyzo  阅读(66)  评论(0)    收藏  举报