[HDU5794]A Simple Chess
Description
There is a \(n×m\) board, a chess want to go to the position \((n,m)\) from the position \((1,1)\).
The chess is able to go to position \((x_2,y_2)\) from the position \((x_1,y_1)\), only and if only \(x_1,y_1,x_2,y_2\) is satisfied that \((x_2−x_1)^2+(y_2−y_1)^2=5, x_2>x_1, y_2>y_1\).
Unfortunately, there are some obstacles on the board. And the chess never can stay on the grid where has a obstacle.
I want you to tell me, There are how may ways the chess can achieve its goal.
Input
The input consists of multiple test cases.
For each test case:
The first line is three integers, \(n,m,r,(1\leqslant n,m\leqslant 10^{18},0\leqslant r\leqslant100)\), denoting the height of the board, the weight of the board, and the number of the obstacles on the board.
Then follow \(r\) lines, each lines have two integers, \(x,y(1\leqslant x\leqslant n,1\leqslant y\leqslant m)\), denoting the position of the obstacles. please note there aren't never a obstacles at position \((1,1)\).
Output
For each test case,output a single line "Case #x: y", where x is the case number, starting from 1. And y is the answer after module 110119.
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
尽管本题是走日字,但由于每次必须向坐标更大的地方跳,故实际上和普通的走法无较大区别,需要注意的一点是要判断一个点是否能通过跳日字到达另一个点
对于障碍点的计算,记\(A\)到终点的所有路径数为\(S_A\),记\(T_A\)为\(A\)出发不经过任何障碍点到达终点的路径数,则有\(T_A=S_A-\sum\limits_{A<B}T_B\),其中\(B\)为障碍点,\(A<B\)表示\(A\)的坐标严格小于\(B\),即\(A\)可以通过某些方式跳到\(B\)
我们将起点\(O\)也加入障碍点,最后算出的\(T_O\)即为答案
注意在计算的时候,组合数会非常大,因此需要用到Lucas定理:\(\binom{n}{m}\equiv\binom{n\%p}{m\%p}\binom{n/p}{m/p} \% p\)
/*program from Wolfycz*/
#include<map>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Fi first
#define Se second
#define ll_inf 1e18
#define MK make_pair
#define sqr(x) ((x)*(x))
#define pii pair<int,int>
#define int_inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>inline T frd(T x){
int f=1; char ch=gc();
for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
template<typename T>inline T read(T x){
int f=1; char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x<0) putchar('-'),x=-x;
if (x>9) print(x/10);
putchar(x%10+'0');
}
const int N=1e3,P=110119;
struct node{
ll x,y;
node(ll _x=0,ll _y=0){x=_x,y=_y;}
void clear(){x=y=0;}
void insert(ll _x,ll _y){x=_x,y=_y;}
void print(){printf("%lld %lld\n",x,y);}
bool operator <(const node &tis)const{return x!=tis.x?x<tis.x:y<tis.y;}
bool operator ==(const node &tis)const{return x==tis.x&&y==tis.y;}
}Obstacles[N+10];
int fac[P+10],inv[P+10];
int C(ll n,ll m){
if (n<m) return 0;
if (n<P&&m<P) return 1ll*fac[n]*inv[m]%P*inv[n-m]%P;
return 1ll*C(n/P,m/P)*C(n%P,m%P)%P;
}
void prepare(){
fac[0]=inv[0]=inv[1]=1;
for (int i=1;i<P;i++) fac[i]=1ll*i*fac[i-1]%P;
for (int i=2;i<P;i++) inv[i]=1ll*(P-P/i)*inv[P%i]%P;
for (int i=1;i<P;i++) inv[i]=1ll*inv[i-1]*inv[i]%P;
}
int solve(ll x,ll y){
ll delta=abs(x-y),cnt=(min(x,y)-delta)/3;
return C((cnt<<1)+delta,cnt);
}
bool Check(ll x,ll y){
ll delta=abs(x-y);
if (min(x,y)<delta) return 0;
if ((min(x,y)-delta)%3) return 0;
return 1;
}
int Ans[N+10];
void init(){
memset(Ans,0,sizeof(Ans));
for (int i=0;i<=N;i++) Obstacles[i].clear();
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
prepare();
ll n,m; int r,Case=0;
while (scanf("%lld%lld%d",&n,&m,&r)!=EOF){
int cnt=0; bool Flag=0;
n--,m--; init();
for (int i=1;i<=r;i++){
ll x=read(0ll)-1,y=read(0ll)-1;
if (x==n&&y==m) Flag|=1;
if (!Check(x,y)) continue;
Obstacles[++cnt].insert(x,y);
}
Obstacles[++cnt].insert(n,m);
if (!Check(n,m)||Flag){
printf("Case #%d: 0\n",++Case);
continue;
}
sort(Obstacles+1,Obstacles+1+cnt);
for (int i=1;i<=cnt;i++){
Ans[i]=solve(Obstacles[i].x,Obstacles[i].y);
for (int j=1;j<i;j++){
if (Obstacles[j]<Obstacles[i]){
ll X_i=Obstacles[i].x,Y_i=Obstacles[i].y;
ll X_j=Obstacles[j].x,Y_j=Obstacles[j].y;
if (!Check(X_i-X_j,Y_i-Y_j)) continue;
Ans[i]=(Ans[i]-1ll*Ans[j]*solve(X_i-X_j,Y_i-Y_j)%P)%P;
}else break;
}
Ans[i]=(Ans[i]+P)%P;
}
printf("Case #%d: %d\n",++Case,Ans[cnt]);
}
return 0;
}