Problem Description
(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
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, x,y(1≤x≤n,1≤y≤m) , denoting the position of the obstacles. please note there aren't never a obstacles at position (1,1) .
Output
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
Case #1: 1 Case #2: 0 Case #3: 2 Case #4: 1 Case #5: 5
题意:走日子格的棋子(类似马)要从(1,1)格跳到(N,M)格,(N,M<=10^18),棋盘上有至多100个路障。起点不会是路障。
思路:多校赛上次有个算棋子的题四种情况其中就有这个马的情况,不过是算先手后手必胜策略。这次思路类似。首先棋盘太大肯定是不能从下标下手的,但是路障只有100个,我们就挨个考虑路障。那么在无路障的情况下要怎么从一点到另一点呢?日子格满足横纵坐标分别加2加1或者加1加2,也就是说ΔX=x2-x1和ΔY=y2-y1应该满足:
1.ΔX=2a+b ΔY=2b+a 其中a是走横2格纵1格,b是纵2格横1格。
2.共方案数应该为C(a+b)(a),只是每次走时横纵抉择上的不同。
那么我们需要一个计算大组合数的方法:Lucas定理。
那么解决了白棋盘的情况——任意两点没有障碍的方案数都可以很快得出了——我们怎么处理100个障碍呢?
100个?xjb搞哇!……我一开始就想到了是容斥,计算第i个障碍处之前经过了j个障碍的方案数,j为偶数就减去,为奇数就加上,维护最后的总方案数。
但是GG了……幸亏WZJRJ28很清醒,想到了另一种类似容斥的方法:计算起点到障碍点的方案数,并计算减去该点对之后点的影响。——当然这样需要对所有障碍建图,每个障碍对其所有的右下的障碍连边。——这大概也是我前一个方法orz的原因吧,由于懒没敲建图直接xjbDP,O(N^3)不说还逻辑上出了毛病……坑了队友一波……还好成老师回老家结婚也不忘记帮忙,帮忙切了两个打表题,让我们队进了前200……万恶的罚时TAT
代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<deque>
using namespace std;
typedef long long ll;
int p=110119;
ll N,M,Ans;
int tot,R;
int effect[110];
vector <int> G[110];
deque <int> Q;
ll obx[110],oby[110];
ll st[110],en[110];
ll dis[110][110];
ll f[112000];
void init(int p)
{ //f[n] = n!
f[0] = 1;
for (int i=1; i<=p; ++i) f[i] = f[i-1] * i % p;
}
ll pow_mod(ll a, ll x, int p)
{
ll ret = 1;
while (x) {
if (x & 1) ret = ret * a % p;
a = a * a % p;
x >>= 1;
}
return ret;
}
ll Lucas(ll n, ll k, int p)
{ //C (n, k) % p
ll ret = 1;
while (n && k) {
ll nn = n % p, kk = k % p;
if (nn < kk) return 0; //inv (f[kk]) = f[kk] ^ (p - 2) % p
ret = ret * f[nn] * pow_mod (f[kk] * f[nn-kk] % p, p - 2, p) % p;
n /= p, k /= p;
}
return ret;
}
ll dp[101];
ll WALK(ll n,ll m)
{
if(n<=0 || m<=0)
return 0;
if((n+m)%3!=0)
return 0;
ll X=n-(n+m)/3;
ll Y=m-(n+m)/3;
if(X<0 || Y<0)
return 0;
return Lucas(X+Y,X,p);
}
int main()
{
init (p);
int t=0;
ll tempx,tempy;
bool flag,WTF;
while(scanf("%I64d%I64d%d",&N,&M,&tot)!=EOF)
{
WTF=false;
memset(dp,0,sizeof(dp));
memset(st,0,sizeof(st));
memset(en,0,sizeof(en));
memset(dis,0,sizeof(dis));
for(int i=1;i<=100;i++)
G[i].clear();
R=0;
for(int i=1;i<=tot;i++)
{
scanf("%I64d%I64d",&tempx,&tempy);
if(tempx==N&&tempy==M)WTF=true;
flag=false;
for(int j=1;j<=R;j++)
{
if(tempx==obx[j]&&tempy==oby[j])
flag=true;
if(tempx>N || tempy>M)
flag=true;
}
if(!flag)
{
R++;
obx[R]=tempx;
oby[R]=tempy;
}
}
R++;
obx[R]=N;
oby[R]=M;
memset(effect,0,sizeof(effect));
for(int i=1;i<=R;i++)
{
for(int j=1;j<=R;j++)
{
if(obx[i]<obx[j]&&oby[i]<oby[j])
{
G[i].push_back(j);
effect[j]++;
}
}
}
for(int i=1;i<=R;i++)
{
st[i]=WALK(obx[i]-1,oby[i]-1);
en[i]=WALK(N-obx[i],M-oby[i]);
}
for(int i=1;i<=R;i++)
for(int j=1;j<=R;j++)
dis[i][j]=WALK(obx[j]-obx[i],oby[j]-oby[i]);
for(int i=1;i<=R;i++)
if(effect[i]==0)
Q.push_back(i);
for(int i=1;i<=R;i++)
dp[i]=st[i];
int len,temp;
while(!Q.empty())
{
len=Q.size();
for(int k=1;k<=len;k++)
{
temp=Q.front();
Q.pop_front();
for(unsigned int i=0;i<G[temp].size();i++)
{
dp[G[temp][i]]-=(dp[temp]*dis[temp][G[temp][i]])%p;
dp[G[temp][i]]+=p;
dp[G[temp][i]]%=p;
effect[G[temp][i]]--;
if(effect[G[temp][i]]==0)
Q.push_back(G[temp][i]);
}
}
}
Ans=dp[R];
if(N==1&&M==1)
Ans=1;
if(WTF)
Ans=0;
printf("Case #%d: %I64d\n",++t,Ans);
}
return 0;
}