思路
出题人说这是一道Lucas+容斥的水题。。
哭晕在厕所。。
写一下是按马(没有马脚)的行走规则来移动的,且每次只能移动到右下方。
左上角坐标为
(1,1)
,右下角坐标为
(n,m)
注意左上角没有障碍物但是右下角可能有.
步数 | 坐标 | 方案数 |
---|---|---|
1 | (1,1) | 1 |
2 | (2,3) | 1 |
2 | (3,2) | 1 |
3 | (3,5) | 1 |
3 | (4,4) | 2 |
3 | (5,3) | 1 |
4 | (4,7) | 1 |
4 | (5,6) | 3 |
4 | (6,5) | 3 |
4 | (7,4) | 1 |
所以方案数就是一个侧着的杨辉三角
步数:
(x+y)/3
能够到达的点的坐标满足:
(x+y)mod3=2
所以答案就是 (1,1) 到 (n,m) 的方案数,减去以障碍物 (x,y) 为中心的两端方案数的乘积,因为有可能重复减,所以要容斥一下(这也叫容斥真是醉了),对于每个障碍物,遍历减去之前计算过的障碍物的方案数与障碍物到这个点的方案数的乘积
代码
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
#define debug(a) printf("a =: %d\n",a);
const int INF=0x3f3f3f3f;
const int maxn=1e2+50;
const double PI=acos(-1);
using namespace std;
/*
逆元定义:x为a的乘法逆元,(b/a) (mod Mod) = (b * x) (mod Mod)
x表示a的逆元。并且 a*x ≡ 1 (mod Mod )
注意:只有当a与Mod互质的时候才存在逆元
以下两种写法都必须要求MOD为素数
*/
typedef long long ll;
const int Mod=110119;
ll invs[Mod+50];
ll fac[Mod+50];
//1 预处理
void initInv(int Mod){
invs[1]=1;
for (int i=2;i<Mod;i++)
invs[i]=invs[Mod%i]*(Mod-Mod/i)%Mod;
}
//2 直接求
ll inv(int a,int mod){
return(a==1?1:inv(mod%a,mod)*(mod-mod/a)%mod);
}
//3 inv(x)=x^(mod-2)
ll qPow(ll x,ll n,ll mod){
ll ret=1;
while(n){
if (n&1) ret=(ret*x)%mod;
x=(x*x)%mod;
n>>=1;
}
return ret; //x^n%mod
}
void initFac(int Mod){
//n!
fac[0]=1;
for(int i=1;i<=Mod;i++){
fac[i]=fac[i-1]*i%Mod;
}
}
ll lucas(ll n,ll k,ll mod){
//C_n^k%mod
if (n<0 || k<0 || k>n) return 0;
ll ret=1;
while(n && k){
ll np=n%mod,kp=k%mod;
if (np<kp) return 0;
ret=(ret*fac[np]%mod)*invs[fac[kp]*fac[np-kp]%mod]%mod;
// ret=(ret*fac[np]%mod)*inv(fac[kp]*fac[np-kp]%mod,mod)%mod;
// ret=(ret*fac[np]%mod)*qPow(fac[kp]*fac[np-kp]%mod,mod-2,mod)%mod;
n/=mod; k/=mod;
}
return ret;
}
typedef pair<ll,ll> Pll;
ll dp[maxn];
ll get(ll x,ll y){
if (x<=0 || y<=0) return 0;
ll step=x+y-2;
ll lay=step/3;
ll ways=min(x,y)-lay-1;
if (step%3) return 0;
return lucas(lay,ways,Mod);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
// freopen("1002.in","r",stdin);
#endif
initFac(Mod);
initInv(Mod);
int r;
ll n,m;
int cs=0;
while(~scanf("%lld %lld %d",&n,&m,&r)){
vector<Pll> v;
mem(dp,0);
ll ans,x,y;
for(int i=0;i<r;i++){
scanf("%lld %lld",&x,&y);
v.push_back(Pll(x,y));
}
v.push_back(Pll(n,m));
sort(v.begin(),v.end());
for(int i=0;i<=r;i++){
ll xi=v[i].first,yi=v[i].second;
dp[i]=get(xi,yi);
for(int j=0;j<i;j++){
ll xj=v[j].first,yj=v[j].second;
dp[i]=(dp[i]-dp[j]*get(xi-xj+1,yi-yj+1)%Mod+Mod)%Mod;
}
}
ans=dp[r];
printf("Case #%d: %lld\n",++cs,ans);
}
return 0;
}