HDU-5794 A Simple Chess

题目描述

棋子在\(n*m\)棋盘上可以走马步(横走\(1\)竖走\(2\)或横走\(2\)竖走\(1\)

只能往格子坐标增大的方向跳,且棋盘中会有一些障碍物

问棋子从\((1,1)\)走到\((n,m)\)有几种方案mod(\(110119\))

Input

输入包含多组数据

第一行三个整数\(n,m,r,(1<=n,m<=1e18,0<=r<=100),\)

接下来\(r\)行,每行两个整数\(x,y,(1<=x<=n,1<=y<=m),\)

表示障碍物位置\((1,1)\)上不会有障碍物

Output

对于每组测试数据,输出一行"Case #x: y",x是组数,y是答案

Sample Input

1 1 0
3 3 0
4 4 1
2 1
4 4 1
3 2
7 10 2
1 2
7 1

Sample Output

Case #1: 1
Case #2: 0
Case #3: 2
Case #4: 1
Case #5: 5

​ 容斥\(dp\)+\(lucas\)定理。

题目要我们求出不碰到任意障碍物的方案数,直接求这个方案数是十分麻烦的。

我们可以转换成从起点出发到第\(i\)个障碍物不碰到任意障碍物的方案数。

我们先把在\((n,m)\)处放置一个障碍物,再把所有的障碍物按照\(x\)排序。

我们定义\(dp[i]\)表示从起点出发到第\(i\)个障碍物不碰到任意障碍物的方案数。

\(calc[x1,y1,x2,y2]\)表示从\(x1,y1\)到第\(x2,y2\)个障碍物的方案数。

排序好之后,我们对于第\(i\)个障碍物:

\(dp[i]=calc[1,1,x_i,y_i]-\sum calc(x_j,y_j,x_i,y_i)*dp[j],(j=起点到第i的路径上的障碍)\)

现在我们就是要求出\(calc(x1,y1,x2,y2)\)


首先设\(X=x2-x1,Y=y2-y1\),横走\(1\)竖走\(2\)走了\(a\)步,或横走\(2\)竖走\(1\)走了\(b\)步。

所以我们有\(a+2*b=X\)\(b+2*a=Y\)

我们可以解出\(a,b\),若\(a,b\)​无整数解则无法从\((x1,y1)\)\((x2,y2)\)

解出了\(a,b\)后答案就是\(C(a+b,a)\)了。

只是\(a,b\)比较大,而我们发现模数\(110119\)是一个质数。

所以我们可以利用\(lucas\)定理。


\(lucas\)定理:当\(p\)为质数时,\(C(a,b)\%p=C(a/p,b/p)*C(a\%p,b\%p)\%p\)

代码如下

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;

#define int long long
#define reg register
#define Raed Read
#define clr(a,b) memset(a,b,sizeof a)
#define Mod(x) (x>=mod)&&(x-=mod)
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a))
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
#pragma GCC target("avx,avx2,sse4.2")
#pragma GCC optimize(3)

inline int Read(void) {
	int res=0,f=1;
	char c;
	while(c=getchar(),c<48||c>57)if(c=='-')f=0;
	do res=(res<<3)+(res<<1)+(c^48);
	while(c=getchar(),c>=48&&c<=57);
	return f?res:-res;
}

template<class T>inline bool Min(T &a, T const&b) {
	return a>b?a=b,1:0;
}
template<class T>inline bool Max(T &a, T const&b) {
	return a<b?a=b,1:0;
}

const int N=105,M=1e5+5,mod=110119;

bool MOP1;

struct node {
	int x,y;
	bool operator<(node _)const {
		if(x==_.x)return y<_.y;
		return x<_.x;
	}
} A[N];

int dp[N];

bool MOP2;

int Fac[mod+5],Inv[mod+5],V[mod+5];

int C(int a,int b) {
	if(a<b||b<0)return 0;
	if(a<mod&&b<mod)return 1ll*Fac[a]*((1ll*Inv[a-b]*Inv[b])%mod)%mod;
	return (1ll*C(a%mod,b%mod)*C(a/mod,b/mod)%mod)%mod;
}

inline int calc(int x,int y) {
	int tot=x+y;
	if(tot%3)return 0;
	int a=x-tot/3,b=y-tot/3;
	return C(a+b,a);
}

inline void _main(void) {
	int Case=0,n,m,k;
	Fac[0]=Inv[0]=Fac[1]=V[1]=Inv[1]=1ll;
	ret(i,2,mod) {
		Fac[i]=(1ll*Fac[i-1]*i)%mod;
		V[i]=1ll*(mod-mod/i)*V[mod%i]%mod;
		Inv[i]=(1ll*Inv[i-1]*V[i])%mod;
	}
	while(~scanf("%lld %lld %lld",&n,&m,&k)) {
		int f=0;
		rep(i,1,k) {
			A[i]=(node)<%Read(),Read()%>;
			if(A[i].x==n&&A[i].y==m)f=1;
		}
		A[++k]=(node)<%n,m%>,sort(A+1,A+k+1);
		clr(dp,0);
		rep(i,1,k) {
			dp[i]=calc(A[i].x-1,A[i].y-1);
			ret(j,1,i)if(A[j].y<=A[i].y) {
				int res=(dp[j]*calc(A[i].x-A[j].x,A[i].y-A[j].y))%mod;
				dp[i]=((dp[i]-res)%mod+mod)%mod;
			}
		}
		printf("Case #%lld: %lld\n",++Case,dp[k]);
	}

}

signed main() {
	_main();
	return 0;
}
posted @ 2019-08-29 15:22  dsjkafdsaf  阅读(160)  评论(0编辑  收藏  举报