记录一个菜逼的成长。。
参考自:
http://blog.csdn.net/lqybzx/article/details/52124404
http://www.cnblogs.com/zhengguiping–9876/p/5785594.html
貌似之前见过一些这种棋盘算方案数的的题。。
或许算经典的题型吧。
题目大意:
有一个n*m的棋盘,有一个棋子只能走“日”字形。
棋盘上有一些障碍物。
问从(1,1)走到(n,m)的方案数。
图片来源:http://www.cnblogs.com/zhengguiping–9876/p/5785594.html
容斥应该算是一种逆向思维吧。
直接求不好求。
我们可以用总方案数减去不可行的方案数。
我们用一个数组来ans[i]来表示到不经过障碍物到达第i个障碍物的方案数。
需要先对障碍物进行从左到右排序。
对于每一个障碍物,
先求出到达这个障碍物i的方案数,
再枚举这个障碍物之前的障碍物j,减去从(1,1)到j障碍物*从j障碍物到i障碍物的方案数,两个过程均不经过中间障碍物。
我们将终点放入障碍物数组,那么答案就是ans[r+1];
由图上的路径可以看出是杨辉三角的构造。
我们需要将坐标转换一下,使得方案数可以用组合数求出。
求组合数可以用Lucas定理的模板。
注意:
如果不用预处理阶乘数组的模板,会吃T.
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <list>
#include <deque>
#include <cctype>
#include <bitset>
#include <cmath>
#include <cassert>
using namespace std;
#define ALL(v) (v).begin(),(v).end()
#define cl(a,b) memset(a,b,sizeof(a))
#define bp __builtin_popcount
#define pb push_back
#define mp make_pair
#define fin freopen("D://in.txt","r",stdin)
#define fout freopen("D://out.txt","w",stdout)
#define lson t<<1,l,mid
#define rson t<<1|1,mid+1,r
#define seglen (node[t].r-node[t].l+1)
#define pi 3.1415926
#define exp 2.718281828459
#define lowbit(x) (x)&(-x)
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;
typedef vector<PII> VPII;
const int INF = 0x3f3f3f3f;
const LL MOD = 110119;
struct node{
LL x,y;
}a[110];
bool cmp(node a,node b)
{
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
LL fact[110119] = {1};
void init(int n)
{
for( int i = 1; i <= n; i++ ){
fact[i] = fact[i-1] * i % MOD;
}
}
LL PowerMod(LL a, LL b, LL c)
{
LL ans = 1;
a = a % c;
while(b>0)
{
if(b % 2 == 1)
ans = (ans * a) % c;
b = b/2;
a = (a * a) % c;
}
return ans;
}
LL C(LL n, LL m)
{
if(m>n)return 0;
if(m == 0)return 1;
LL ans = fact[n] * PowerMod(fact[m], MOD-2,MOD) % MOD * PowerMod(fact[n-m], MOD-2,MOD) % MOD;
return ans;
}
LL Lucas(LL n, LL m)
{
if(n<0 || m<0)return 0;///会出现不可达的情况,所以注意判断,否则会re;
if(m > n) return 0;
if(m == 0) return 1;
return C(n%MOD, m%MOD) * Lucas(n/MOD, m/MOD) % MOD;
}
LL ans[110];
LL solve(int i,int j)
{
LL n = a[j].x - a[i].x,m = a[j].y - a[i].y;
if((n+m)%3LL != 0)return 0;
LL step = (n + m) / 3LL;
n -= step;
m -= step;
if(n < 0 || m < 0)return 0;
return Lucas(n+m,m);
}
int main()
{
init(110119LL);
LL n,m;
int r,cas = 1;
while(~scanf("%lld%lld%d",&n,&m,&r)){
for( int i = 1; i <= r; i++ ){
scanf("%lld%lld",&a[i].x,&a[i].y);
}
sort(a+1,a+1+r,cmp);
a[0].x = 1,a[0].y = 1;
a[r+1].x = n,a[r+1].y = m;
for( int i = 1; i <= r + 1; i++ ){
ans[i] = solve(0,i);
for( int j = 1; j < i; j++ ){
ans[i] = (ans[i] - ans[j] * solve(j,i) % MOD + MOD) % MOD;
}
}
printf("Case #%d: %lld\n",cas++,ans[r+1]);
}
return 0;
}