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

浙公网安备 33010602011771号