A Simple Chess
Total Submission(s): 1081 Accepted Submission(s): 291
Problem 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
(x2,y2)
from the position
(x1,y1)
, only and if only
x1,y1,x2,y2
is satisfied that
(x2−x1)2+(y2−y1)2=5, x2>x1, y2>y1
.
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≤n,m≤1018,0≤r≤100)
, 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,
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
Author
UESTC
Source
2016 Multi-University Training Contest 6
根据公式一推,很容易发现是按象棋中马来移动的。
不存在马脚的一说。
然后给出r个陷阱,要求
n×m
的图上,不能走到陷阱情况下从点
(1,1)
走到终点
(n,m)
的走法。
已知陷阱不会出现在起点 (1,1)
首先需要推得对于任意无陷阱的 n×m 的图中,走到终点 (n,m) 的走法。
打个表可以看出是杨辉三角,也就是组合数,推到 n×m 的图上就是 Cnn+m−23−n+m−23−1) 。
但是n和m很大,就要用到Lucas,正经的Lucas我们发现会TLE
因为Lucas里的那个
Cnm
也是O(mod)的。因为模数很小,可以用最原始的公式
Cnm=m!n!(m−n)!
这样可以预处理出来阶乘,因为要取模,逆元也一并用快速幂搞出来即可。
以上是Lucas的部分。
因为要去掉经过陷阱到达
(n,m)
的路径,这里用到一个小容斥。
定义
dp[i]
表示从
(1,1)
不经过陷阱到达第
i
个陷阱的路径数目。
预先对陷阱进行先行后列的二级排序。这样保证遍历到第
这样最终
dp[i]
就表示从
(1,1)
不经过任何陷阱到达
i
陷阱的路径数。
可以把
注意对点 (n,m) 的可达性的判断,因为少了个判断导致对负数进行了组合数运算=。=RE半天
代码如下:
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<LL,LL>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)
using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 10000;
const int mod = 110119;
const double eps = 1e-8;
LL p[110120];
LL inv[110120];
LL pow_m(LL a,int b)
{
LL ans = 1;
while(b)
{
if(b&1) ans = (ans*a)%mod;
b >>= 1;
a = (a*a)%mod;
}
return ans;
}
void init()
{
p[0] = 1;
for(int i = 1; i < mod; ++i) p[i] = (i*p[i-1])%mod;
for(int i = 0; i < mod; ++i) inv[i] = pow_m(p[i],mod-2);
}
LL C(int m,int n)
{
if(n > m) return (LL)0;
if(m == n) return (LL)1;
return (((p[m]*inv[n])%mod)*inv[m-n])%mod;
}
LL Lucas(LL n,LL m)
{
if(m == 0) return(LL)1;
return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod;
}
LL got(LL n,LL m)
{
if(n <= 0 || m <= 0) return 0;
LL mn,mx;
mn = min(m,n);
mx = max(m,n);
LL v = (mn+mx-2)/3;
if((mn+mx-2)%3 || v+1 > mn) return 0;
return Lucas(v,mn-v-1);
}
Pr pr[111];
LL dp[111];
int main()
{
//fread("");
//fwrite("");
LL n,m;
int r,z = 1;
init();
while(~scanf("%lld%lld%d",&n,&m,&r))
{
for(int i = 0; i < r; ++i)
{
scanf("%lld%lld",&pr[i].first,&pr[i].second);
}
sort(pr,pr+r);
pr[r].first = n;
pr[r].second = m;
for(int i = 0; i <= r; ++i)
{
dp[i] = got(pr[i].first,pr[i].second);
for(int j = 0; j < i; ++j)
{
dp[i] = (((dp[i]-(dp[j]*got(pr[i].first-pr[j].first+1,pr[i].second-pr[j].second+1))%mod)%mod)+mod)%mod;
}
}
printf("Case #%d: %lld\n",z++,dp[r]);
}
return 0;
}