概述
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5794
【题意】给定一个n*m的棋盘,一个棋子要从(1,1)移动到(n,m),棋子只能向右下如同象棋中马一样按照日字移动,在棋盘上存在r个障碍物,棋子不能落在障碍物上,问有几种走法。
【分析】简单打表可以看出不存在障碍物时棋子走法是一个斜着的杨辉三角。由于每次棋子移动的横纵坐标差值和一定是3,所以棋子所在的层数n等于(x+y)/3。棋子从(1,1)点开始移动,只有满足(x+y)%3==2 && x>=n+1 && y>=n+1的点棋子才能到达。以一条边界线上的点看,所有的x=n+1,那么同层棋子每向里移动一格,x+1,y-1.于是可以计算得到棋子在n层的位置m=x-n-1。根据点所在的层数n和位置m,可以利用组合数快速计算出到达该点的走法为C(n,m)种。本题中由于棋盘界限很大,但取模数为110119,刚好满足鲁卡斯定理的要求,可以利用鲁卡斯定理快速求大组合数取模的结果。接着分析障碍物造成的影响。首先排除不影响走法的障碍物。以s_obs[i]表示起点到障碍物i所在点的走法,obs_e[i]表示障碍物i所在点到(n,m)的走法。那么减少的走法就是s_obs[i]*obs_e[i]。由于多个障碍物会相互影响,直接减会多减了,需要容斥处理相互影响的障碍物(PS:比赛时怎么算都觉得容斥会超时ORZ。。。虽然最后没办法硬着头皮上了。。竟然过了)
【代码】
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define LL long long
const int mod=110119;
struct Node{
LL x,y;
}obs[110];
bool cmp(Node n1,Node n2){
return (n1.x+n1.y)/3<(n2.x+n2.y)/3;
}
LL waynum[110][110];
LL fac[120010];
LL s_obs[110];
LL obs_e[110];
LL ans;
int cnt=0;
int numtag[110];
void Extgcd(LL a,LL b,LL &x,LL &y){
if(b==0){
x=1;
y=0;
return;
}
Extgcd(b,a%b,x,y);
LL tmp=x;
x=y;
y=tmp-(a/b)*y;
}
LL C(LL n,LL m){
if(m>n) return 0;
if(n==m) return 1;
LL tt,x,y;
tt=m;
m=fac[n];
n=(fac[tt]*fac[n-tt]%mod);
Extgcd(n,mod,x,y);
x*=m;
x%=mod;
if(x<0) x+=mod;
return x;
}
LL lucas(LL n,LL m){
if(m > n / 2) m = n - m;
if(m==0) return 1;
return C(n%mod,m%mod)*lucas(n/mod,m/mod)%mod;
}
LL cal(LL x,LL y){
LL n=(x+y)/3;
LL m=y-n-1;
return lucas(n,m);
}
bool canbe(LL x,LL y){
if(x<0 || y<0 || (x+y)%3!=2)
return false;
LL n=(x+y)/3;
if(x<n+1 || y<n+1)
return false;
return true;
}
void dfs(int pre,int pos,int d,LL tmp){
if(tmp == 0) return;
if(d&1)
ans=(ans-tmp*obs_e[pos] % mod)%mod;
else
ans=(ans+ tmp * obs_e[pos] % mod)%mod;
for(int i=pos+1;i<cnt;i++)
dfs(pos,i,d+1,tmp*waynum[pos][i] % mod);
}
void init(){
fac[0]=fac[1]=1;
for(int i=2;i<120000;++i)
fac[i]=(fac[i-1]*i)%mod;
}
int main(){
init();
int r,cas=1;
LL n,m,x,y;
while(scanf("%I64d %I64d %d",&n,&m,&r)!=EOF)
{
memset(s_obs,0,sizeof(s_obs));
memset(obs_e,0,sizeof(obs_e));
cnt = 0;
for(int i=0;i<r;++i)
{
scanf("%I64d %I64d",&x,&y);
if(canbe(x,y))
{
obs[cnt].x=x;
obs[cnt++].y=y;
}
}
LL tmpx,tmpy;
LL cn=(n+m)/3,cm;
if(!canbe(n,m))
{
printf("Case #%d: 0n",cas++);
continue;
}
sort(obs,obs+cnt,cmp);
cm=n-cn-1;
ans=lucas(cn,cm);
for(int i=0;i<cnt;++i)
{
s_obs[i]=cal(obs[i].x,obs[i].y);
tmpx=n-obs[i].x+1;
tmpy=m-obs[i].y+1;
if(canbe(tmpx,tmpy))
obs_e[i]=cal(tmpx,tmpy);
else
obs_e[i] = 0;
for(int j=i+1;j<cnt;++j){
tmpx=obs[j].x-obs[i].x+1;
tmpy=obs[j].y-obs[i].y+1;
if(canbe(tmpx,tmpy)){
waynum[i][j]=cal(tmpx,tmpy);
}
else
waynum[i][j]=0;
}
}
for(int i=0;i<cnt;++i)
dfs(-1,i,1,s_obs[i]);
ans=(ans+mod)%mod;
printf("Case #%d: %I64dn",cas++,ans);
}
}
最后
以上就是大方睫毛为你收集整理的HDU5794 A Simple Chess的全部内容,希望文章能够帮你解决HDU5794 A Simple Chess所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复