题意:
棋盘上的一个棋子,给出他的两种移动方式:
1. (u,v)−>(u+Ax,v+Ay) ( u , v ) − > ( u + A x , v + A y )
2. (u,v)−>(u+Bx,v+By) ( u , v ) − > ( u + B x , v + B y )
现给出一些不能走的障碍点n个,求(0,0)到(Ex,Ey)的方案数
|Ax|,|Ay|,|Bx|,|By|<=500,0<=n,Ex,Ey<=500;Ax∗By−Ay∗Bx≠0 | A x | , | A y | , | B x | , | B y | <= 500 , 0 <= n , E x , E y <= 500 ; A x ∗ B y − A y ∗ B x ≠ 0
Solution:
因为题目保证了 Ax∗By−Ay∗Bx≠0 A x ∗ B y − A y ∗ B x ≠ 0 ,所以从原点出发走到某个点所需的两种走法的次数是唯一的
具体可以列出方程,设到点(X,Y)分别需要a,b步
{ Ax∗a+Bx∗b=XAy∗a+By∗b=Y { A x ∗ a + B x ∗ b = X A y ∗ a + B y ∗ b = Y
我们只要把指定点的a,b算出来后,问题就转化为一个只能往右或者往上的常规路径计数问题
但是(Ex,Ey)所对应的a,b可能很大,所以我们不能递推地算
考虑容斥:
我们知道如果没有障碍的话从 (0,0) ( 0 , 0 ) 到 (n,m) ( n , m ) 的方案数为 Cnn+m C n + m n
设 f[i] f [ i ] 为从原点出发到达第i个关键点的方案数, g[i][j] g [ i ] [ j ] 表示从i到j的方案数
那么我们可以得到: f[i]=g[0][i]−∑i−1j=1f[j]∗g[j][i] f [ i ] = g [ 0 ] [ i ] − ∑ j = 1 i − 1 f [ j ] ∗ g [ j ] [ i ]
显然g数组就是一个组合数,预处理阶乘以及阶乘的逆元即可
复杂度 O(n2) O ( n 2 )
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
const int N=1000000;
int n,m,t,cnt;
int f[510];
int a,b,c,d,mi[1000010],inv[1000010];
struct P{
int x,y;
}p[510];
bool calc(int &x,int &y)
{
int s1=x*d-y*c,t1=a*d-b*c,s2=x*b-y*a,t2=c*b-d*a;
if (t1==0||t2==0) return 0;
if (s1%t1) return 0;else x=s1/t1;
if (s2%t2) return 0;else y=s2/t2;
return 1;
}
int fast_pow(int x,int a)
{
int ans=1;
for (;a;a>>=1,x=1ll*x*x%mod)
{
if (a&1) ans=1ll*ans*x%mod;
}
return ans;
}
bool cmp(P a,P b){
if(a.x==b.x) return a.y<b.y; return a.x<b.x;}
int C(int n,int m){
if (n<m) return 0;return 1ll*mi[n]*inv[m]%mod*inv[n-m]%mod;}
int main()
{
scanf("%d%d%d",&n,&m,&t);
scanf("%d%d%d%d",&a,&b,&c,&d);
if ((!calc(n,m))||n<0||m<0) {
printf("0\n");return 0;}
for (int x,y,i=1;i<=t;i++)
{
scanf("%d%d",&x,&y);
if (calc(x,y)&&x>=0&&y>=0&&x<=n&&y<=m) p[++cnt]={
x,y};
}
mi[0]=1;
for (int i=1;i<=N;i++) mi[i]=1ll*mi[i-1]*i%mod;
inv[N]=fast_pow(mi[N],mod-2);
for (int i=N-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
p[++cnt]={n,m};
sort(p+1,p+1+cnt,cmp);
f[0]=1;
for (int i=1;i<=cnt;i++)
{
f[i]=C(p[i].x+p[i].y,p[i].x);
for (int j=1;j<i;j++)
f[i]=(1ll*f[i]+mod-(1ll*C(p[i].x-p[j].x+p[i].y-p[j].y,p[i].x-p[j].x)*f[j]%mod))%mod;
}
printf("%d",f[cnt]);
}