概述
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5794
题目大意:
给一个n*m的棋盘,要求从(1,1)走到(n,m),只能以日字的形式走过去,然后不能经过某些坏点,问有几种走法。
范围:
n,m<=10^18,mod=110119。
思路:
和上一题的模型很相似。具体见http://blog.csdn.net/aaaaacmer/article/details/52132704。
但是要进行转化。转换方式比较神奇,就是先将x,y坐标都减1,然后将X=-1/3x+2/3y,Y=2/3x-1/3y。转化以后可以知道,如果新的坐标不为非负整数,就是不可到达的点,然后利用模型直接计算。因为n,m比较大,而mod比较小,所以可以用卢卡斯定理解决。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
#define eps 0.001
#define mod 110119
#define ll __int64
using namespace std;
ll f[200];
struct node{
ll x,y;
}p[200];
bool cmp(node a,node b){
if(a.x!=b.x)return a.x<b.x;
return a.y<b.y;
}
ll PowMod(ll a,ll b,ll MOD){
ll ret=1;
while(b){
if(b&1) ret=(ret*a)%MOD;
a=(a*a)%MOD;
b>>=1;
}
return ret;
}
ll fac[110121];
ll Get_Fact(ll p){
fac[0]=1;
for(ll i=1;i<=p;i++)
fac[i]=(fac[i-1]*i)%p; //预处理阶乘
}
ll Lucas(ll n,ll m,ll p){
ll ret=1;
while(n&&m){
ll a=n%p,b=m%p;
if(a<b) return 0;
ret=(ret*fac[a]*PowMod(fac[b]*fac[a-b]%p,p-2,p))%p;
n/=p;
m/=p;
}
return ret;
}
int main()
{
ll n,m;
int i,j,k,r,tt;
int icase=0;
Get_Fact(mod);
while(~scanf("%I64d%I64d%d",&n,&m,&r)){
icase++;
tt=0;
ll xx,yy;
for(i=1;i<=r;i++){
scanf("%I64d%I64d",&xx,&yy);
xx--;
yy--;
ll x,y;
x=-xx+2*yy;
y=2*xx-1*yy;
if(x%3==0&&y%3==0&&x>=0&&y>=0){
p[++tt].x=x/3;
p[tt].y=y/3;
}
}
printf("Case #%d: ",icase);
ll edx,edy;
edx=-(n-1)+2*(m-1);
edy=2*(n-1)-1*(m-1);
if(!(edx%3==0&&edy%3==0&&edx>=0&&edy>=0)){
printf("0n");
continue;
}
sort(p+1,p+1+tt,cmp);
memset(f,0,sizeof(f));
p[tt+1].x=edx/3;
p[tt+1].y=edy/3;
for(i=1;i<=tt+1;i++){
ll dx,dy;
dx=p[i].x;
dy=p[i].y;
ll tmp=Lucas(dx+dy,dx,mod);
for(j=1;j<i;j++){
if(p[i].x>=p[j].x&&p[i].y>=p[j].y){
ll dxx,dyy;
dxx=p[i].x-p[j].x;
dyy=p[i].y-p[j].y;
tmp-=f[j]*Lucas(dxx+dyy,dxx,mod)%mod;
tmp=(tmp+mod)%mod;
}
}
f[i]=(tmp+mod)%mod;
}
printf("%I64dn",(f[tt+1]+mod)%mod);
}
}
最后
以上就是糟糕西装为你收集整理的hdu5794A Simple Chess(组合数学)的全部内容,希望文章能够帮你解决hdu5794A Simple Chess(组合数学)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复