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
",++Case,dp[k]);
	}

}

signed main() {
	_main();
	return 0;
}
原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11429903.html