【题解】两双手(格路问题)
题目大意:求从\((0,0)\)到\((Ex,Ey)\)不经过给定障碍点的方案数。你每次移动只能是加上向量\(e_1\)或者向量\(e_2\),\(e_1,e_2\)中的基底都是整数。
考虑转化一下这个问题,从某个点走到在他右上角的某点需要加上\(ae_1+be_2\),这样我们就可以解出\(a,b\)。我们把\((a,b)\)拿出来建立新的坐标系,就变成了简单的格路问题了。结合【题解】CF559C C. Gerald and Giant Chess(容斥+格路问题)就可以直接做了。当不存在\((a,b)\)是非负整数解时,可以把这个点删掉。
考虑为什么可以这样解出两个值\((a,b)\)转化,只能在这道题里用吗?实际上,格路问题可以抽象成这样一种问题:
你有两种元素,每种元素每次可以增加一,一次只能加一种元素,元素之间互相独立。现在要你从\((0,0)\)加到\((n,m)\),问你多少组方案。方案的本质是对于加元素的操作构成的合法序列的总数。
用序列的角度看问题,?有\(a_i\)种\(i\)元素,你要好好排列出\(\sum a_i\)长度的序列,问这些序列不同的分布。这就可以拓展为多维的问题。
这应该是此类格路问题的本质。
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
int n,A1,A2,B1,B2;
const int maxn=5e2+5;
const int mod=1e9+7;
typedef pair<int,int> P;
P data[maxn];
int jc[1000001],inv[1000001],cnt,dp[maxn];
inline int ksm(const int&ba,const int&p){
int ret=1;
for(int t=p,b=ba%mod;t;t>>=1,b=1ll*b*b%mod)
if(t&1) ret=1ll*ret*b%mod;
return ret;
}
inline void pre(const int&n){
*jc=*inv=1;
for(int t=1;t<=n;++t) jc[t]=1ll*jc[t-1]*t%mod;
inv[n]=ksm(jc[n],mod-2);
for(int t=n-1;t;--t) inv[t]=1ll*inv[t+1]*(t+1)%mod;
}
inline bool get(P&s){
int x=s.first,y=s.second;
int a=(B2*x-B1*y)/(A1*B2-A2*B1);
int b=(A2*x-A1*y)/(A2*B1-A1*B2);
s=(pair<int,int>){a,b};
return a*A1+b*B1==x&&a*A2+b*B2==y&&a>=0&&b>=0;
}
inline int c(const int&n,const int&m){return n<m?0:1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;}
inline int grid(const int&x,const int&y){return c(x+y,x);}
int main(){
int f=qr(),g=qr();
data[++cnt]=(pair<int,int>){f,g}; n=qr();
A1=qr(); A2=qr();
B1=qr(); B2=qr();
if(!get(data[1])) return !puts("0");
pre(1e6);
for(int t=1,t1,t2;t<=n;++t){
t1=qr(); t2=qr();
data[++cnt]=(pair<int,int>){t1,t2};
if(!(get(data[cnt])&&data[cnt]<=data[1])) --cnt;
}
sort(data+1,data+cnt+1);
for(int t=1;t<=cnt;++t){
dp[t]=grid(data[t].first,data[t].second);
for(int i=1;i<t;++i)
dp[t]=(dp[t]-1ll*dp[i]*grid(data[t].first-data[i].first,data[t].second-data[i].second)%mod+mod)%mod;
}
printf("%d\n",dp[cnt]);
return 0;
}
原文地址:https://www.cnblogs.com/winlere/p/11566828.html
时间: 2024-10-08 13:29:05