题意:
给出两个向量,问多少种方式能够不经障碍点到达终点。
题解:
因为向量可以唯一拆分成两个向量,所以就成了网格图计数。
为了方便,将终点也视为障碍点,设
f
[
i
]
f[i]
f[i]表示到第i个障碍点的方案数。
若不考虑其它障碍点,那么就是
C
x
+
y
y
C_{x+y}^y
Cx+yy,然后减掉从其它障碍点到这个点的情况就好了。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
const LL mod=1e9+7;
LL X,Y,n,x,y,x1,y1;
LL f[510];
bool vis[510];
LL fac[1000010],inv[1000010];
struct node{
LL x,y;
}a[510];
void pre()
{
inv[0]=inv[1]=fac[0]=fac[1]=1;
for(int i=2;i<=1000000;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for(int i=2;i<=1000000;i++) inv[i]=inv[i-1]*inv[i]%mod,fac[i]=fac[i-1]*i%mod;
}
LL C(LL m,LL n) {return fac[m]*inv[m-n]%mod*inv[n]%mod;}
node get(LL s1,LL s2)
{
node ans;ans.x=-1;
LL A=x1*y-x*y1,B=s1*y-x*s2;
if(B%A!=0) return ans;
ans.y=B/A;
A=x;B=s1-ans.y*x1;
//printf("A B:%lld %lld %lld\n",A,B,B%A);
if(A==0) A=y,B=s2-ans.y*y1;
if(B%A!=0) return ans;
ans.x=B/A;
//printf("ans:%lld %lld\n",ans.x,ans.y);
return ans;
}
LL get(LL k)
{
//printf("%lld %lld %lld\n",k,a[k].x,a[k].y);
if(vis[k]) return f[k];
vis[k]=true;f[k]=C(a[k].x+a[k].y,a[k].y);
for(LL i=1;i<=n;i++)
{
if(i==k) continue;
if(a[i].x<=a[k].x&&a[i].y<=a[k].y&&a[i].x!=-1)
{
//printf("%lld->%lld\n",k,i);
LL t1=a[k].x-a[i].x,t2=a[k].y-a[i].y;
(f[k]-=C(t1+t2,t1)*get(i)%mod)%=mod;
}
}
//printf("s:%lld %lld %lld %lld\n",k,f[k],a[k].x+a[k].y,a[k].y);
return f[k];
}
int main()
{
pre();
scanf("%lld %lld %lld",&X,&Y,&n);
scanf("%lld %lld %lld %lld",&x,&y,&x1,&y1);
for(LL i=1;i<=n;i++)
{
LL s1,s2;scanf("%lld %lld",&s1,&s2);
a[i]=get(s1,s2);
}
a[++n]=get(X,Y);
//for(LL i=1;i<=n;i++) printf("%lld %lld\n",a[i].x,a[i].y);
//printf("ok\n");
if(a[n].x==-1) return puts("0"),0;
memset(vis,false,sizeof(vis));
for(LL i=1;i<=n;i++)
{
//printf("%lld\n",i);
if(a[i].x==-1) continue;
if(vis[i]) continue;
f[i]=get(i);
}
printf("%lld\n",(f[n]+mod)%mod);
}