概述
http://acm.hdu.edu.cn/showproblem.php?pid=5794
题意: 马在(1,1)走到(n,m)有些地方设置了障碍物不能走。。问方案总数是多少?
思路:题外话考虑如果不是马是兵。。其实就是一道CF的原题。。。
是马的话其实和兵的思路是一样的,唯一稍微有困难的是要求出(1,1)到(x,y)的方案数 结论是 Lucas ( (x+y)/3 , ((x+y)/3-abs(x-y))/2 )
因为是大组合数取模,显然想到卢卡斯定理,这里就不做详细说明。。。
接下来就是容斥部分。。。首先r有100.。。。肯定不是2^100这样容斥。。太蠢了。。。这个使用的是类似dp的方法,把每个障碍物的最终方案数求出来。。那两个和三个举栗子。。两个肯定是第二个的方案数减去第一个的方案数乘以第一个到第二个的方案数 。。那接下来看第三个。。其实就是第三个的方案数减去第一个的方案数乘以第一个到第三个的方案数并且减去 第二个的方案数乘以第二个到第三个的方案数 。。仔细推敲一下用集合的方法表示一下,我们会发现这恰好就是一个容斥的过程。。归纳一下我们就知道了到第N个的方法了。。。
最后!需要注意的是要判断终点有没有障碍物。。障碍物之间是否可以到达!!!(当时WA到死。。)
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAX 105
using namespace std;
typedef long long LL;
const LL mod = 110119;
const LL p= 110119;
LL dp[MAX];
long long h,w,n;
struct Node{
long long x,y;
bool operator < ( const Node & a ) const{
return x+y < a.x+a.y;
}
bool operator == ( const Node & a ) const{
return x==a.x&&y==a.y;
}
}P[MAX];
long long fac[p+10];
void init(){
int i;
fac[0] =1;
for(i =1; i <= p; i++)
fac[i] = fac[i-1]*i % p;
}
long long pow(long long a, long long b){
long long tmp = a % p, ans =1;
while(b){
if(b &1) ans = ans * tmp % p;
tmp = tmp*tmp % p;
b >>=1;
}
return ans;
}
long long C(long long n, long long m){
if(m > n) return 0;
return fac[n]*pow(fac[m]*fac[n-m], p-2) % p;
}
long long Lucas(long long n, long long m){
if(m<0) return 0;
if(m ==0) return 1;
else return (C(n%p, m%p)*Lucas(n/p, m/p))%p;
}
bool ok(Node T){
if((T.x+T.y)%3==2&&abs(T.x-T.y)<=(T.x+T.y)/3&&T.x<=h&&T.y<=w) return true;
else return false;
}
int main (){
init ();
int cas=1;
while ( scanf ("%lld%lld%lld" , &h , &w , &n )!=EOF ){
int cnt=0;
for ( int i = 0 ; i < n ; i++ ){
scanf ("%lld%lld" , &P[i].x , &P[i].y );
if(ok(P[i])){
P[cnt].x=P[i].x;
P[cnt].y=P[i].y;
cnt++;
}
}
P[cnt].x = h , P[cnt].y = w;
if(!ok(P[cnt])){
printf("Case #%d: 0n",cas++);
continue;
}
sort ( P , P+cnt+1 );
if(cnt>=1&&P[cnt-1]==P[cnt]){
printf("Case #%d: 0n",cas++);
continue;
}
memset ( dp , 0 , sizeof ( dp ));
for ( int i = 0; i <= cnt ; i++ ){
long long x = P[i].x , y = P[i].y;
dp[i] = Lucas ( (x+y)/3 , ((x+y)/3-abs(x-y))/2 );
for ( int j = 0 ; j < i ; j++ ){
long long u = P[j].x , v = P[j].y;
if ( u > x || v > y ) continue;
dp[i] -= Lucas( (x-u+1+y-v+1)/3 , ((x-u+1+y-v+1)/3-abs(x-u-y+v))/2 )*dp[j]%mod;
dp[i] = (dp[i]%mod+mod)%mod;
}
}
printf ( "Case #%d: %lldn" ,cas++, dp[cnt] );
}
}
最后
以上就是懦弱魔镜为你收集整理的HDU 5794 容斥原理+Lucas的全部内容,希望文章能够帮你解决HDU 5794 容斥原理+Lucas所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复