题目链接:戳我
有障碍点的网格图计数
对于一个位置我们一定会通过特定数量的操作来达到这个位置,而且如果有解的话,这个数量一定是确定的。
为什么呢?
我们设(px)为当前点的x坐标,(py)为当前点的y坐标,(ax,ay,bx,by)分别对应题目中含义。那么一定有
通过消元我们可以得到——
然后注意一下分母为0,或者是a,b任意一个不是整数的时候是没有符合题意的解的。
然后我们只记录所有的关键点(也就是障碍点+终点),我们把它们通过排序对应到一个序列上。把它们的xy坐标用两种移动方式分别要移动多少次来替代。注意要排除掉不合法的点。
设(dp[i])表示从原点到第i个点时,不经过任何障碍点的路径条数。
我们知道对于一个确定的点((x,y)),走到它的路径条数为(C_{x+y}^x)。(为什么明明在组合数上是等价的,在这里却不写(C_{x+y}^{y})呢?这个我们在下面再提)
我们有转移方程为(dp[i]=C_{x[i]+y[i]}^{x[i]}-sum_{j=1}^{i-1}dp[j] imes C_{x[i]-x[j]+y[i]-y[j]}^{x[i]-y[i]})
为什么这样子是对的?
自行思考一下嘛这个容斥总觉得有点类似求一堆数中两两配对个数,(x,y)等同于(y,x)那种qwqwq唔感觉说不清楚了。。。。
为什么排序优先级x大于y呢?(不考虑这个问题竟然在darkbzoj上还能过!数据太弱了吧qwqwq)因为我们在下面使用的是(C_{x+y}^x),而当(x>x+y)的时候,return 0。按照给定的两种方式来作为平面上的基底,假设现在它们指向右和上,那么显然左和下是不能过去的。(额,表达能力有点弱,大家理解一下??)如果使用(C_{x+y}^y)的话,我们就要y排序优先级大于x了。
为什么最后输出dp[n]就可以了?因为我们放坐标前就已经按照我们转化的方法把不合法的都扔掉了,终点在排序之后也一定是n(最后面的这个)。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 2500010
#define mod 1000000007
using namespace std;
int n,ax,ay,bx,by;
int nn[MAXN+2],kk[MAXN+2],dp[MAXN];
struct Node{int x,y;}t[MAXN];
bool cmp(Node a,Node b){if(a.x!=b.x)return a.x<b.x;return a.y<b.y;}
inline int pow(int x,int y)
{
int cur_ans=1;
while(y)
{
if(y&1) cur_ans=1ll*cur_ans*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return cur_ans%mod;
}
inline void init()
{
kk[0]=nn[0]=1;
for(int i=1;i<MAXN;i++) kk[i]=1ll*kk[i-1]*i%mod;
nn[MAXN-1]=pow(kk[MAXN-1],mod-2)%mod;
for(int i=MAXN-2;i>=0;i--) nn[i]=1ll*nn[i+1]*(i+1)%mod;
}
inline void solve(int &px,int &py)
{
int cur1=px*by-py*bx;
int cur2=ax*by-ay*bx;
int cur3=px*ay-py*ax;
int cur4=bx*ay-by*ax;
if(!cur2||!cur4) {px=-1,py=-1;return;}
if((cur1%cur2)||(cur3%cur4)) {px=-1,py=-1;return;}
px=cur1/cur2,py=cur3/cur4;
}
inline int calc(int x,int y)
{
if(x<y) return 0;
else return 1ll*kk[x]*nn[y]%mod*nn[x-y]%mod;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
//freopen("ce.out","w",stdout);
#endif
scanf("%d%d%d%d%d%d%d",&t[0].x,&t[0].y,&n,&ax,&ay,&bx,&by);
solve(t[0].x,t[0].y);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&t[i].x,&t[i].y);
solve(t[i].x,t[i].y);
if(t[i].x<0||t[i].y<0||t[i].x>t[0].x||t[i].y>t[0].y) i--,n--;
}
n++;t[n].x=t[0].x,t[n].y=t[0].y;
sort(&t[1],&t[n+1],cmp);
init();
for(int i=1;i<=n;i++)
{
dp[i]=calc(t[i].x+t[i].y,t[i].x);
for(int j=1;j<i;j++)
{
int xx=t[i].x-t[j].x;
int yy=t[i].y-t[j].y;
dp[i]=(dp[i]-1ll*dp[j]*calc(xx+yy,xx)%mod+mod)%mod;
}
}
printf("%d
",dp[n]%mod);
return 0;
}
qwq,今天颓废了一天。。。才写了这一道题qwqwq