hdu 5794 A Simple Chess 【lucas+容斥】

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5794

题意:一个n*m的木板,木板上有障碍物(不能走),现在要你算出从(1,1)到(n,m)有多少方案,只能按照这样的规则走:(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)=5  (x2>x1&&y2>y1).

分析:比赛的时候画图,发现是走到的点是杨辉三角,没有障碍物的时候每个点的方案数就是杨辉三角对应的值C(r-1,c-1)。

对于障碍物,我们可以用容斥来做,将起点终点与障碍物一起起算,设dp[i]表示第i个点作为终点的方案数,障碍物作为终点的方案数为:起点到他的方案数-(他之前除起点外的所有点作为终点的方案数*这些点作为起点到他的方案数)。 dp[i]=(dp[i]-dp[j]*solve(i,j)%mod+mod)%mod;

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 1010
#define Mm 2000005
#define mod 110119
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CLRS(a,b,Size) memset((a),(b),sizeof((a[0]))*(Size+1))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
struct node {
    ll x,y;
    node(){}
    node(ll x,ll y):x(x),y(y){}
    bool operator <(const node a) const {
        if(x==a.x) return y<a.y;
        return x<a.x;
    }
}p[200];
long long F[200010];
void init(long long p) {
    F[0] = 1;
    for(int i = 1;i <= p;i++)
        F[i] = F[i-1]*i % (p);
}
long long inv(long long a,long long m){
    if(a == 1)return 1;
    return inv(m%a,m)*(m-m/a)%m;
}
long long Lucas(long long n,long long m,long long p){
    if(n<0||m<0||m>n) return 0;
    long long ans = 1;
    while(n&&m)
    {
        long long a = n%p;
        long long b = m%p;
        if(a < b)return 0;
        ans = ans*F[a]%p*inv(F[b]*F[a-b]%p,p)%p;
        n /= p;
        m /= p;
    }
    return ans;
}
ll solve(int i,int j) {
    ll sx=p[j].x,sy=p[j].y;
    ll ex=p[i].x,ey=p[i].y;
    ll r=(ex-sx+ey-sy);
    if(r%3||(sx>ex||sy>ey)) return 0;
    r/=3;
    ll c=ex-sx-r;
    return Lucas(r,c,mod);
}
ll dp[200];
int main() {
    ll n,m,a,b;
    int k,cas=0;
    init(mod);
    while(~scanf("%I64d%I64d%d",&n,&m,&k)) {
        for(int i=1;i<=k;i++) {
            scanf("%I64d%I64d",&a,&b);
            p[i]=node(a,b);
        }
        p[++k]=node(1,1);
        p[++k]=node(n,m);
        sort(p+1,p+k+1);
        dp[1]=1;
        for(int i=2;i<=k;i++) {
            dp[i]=solve(i,1);
            for(int j=2;j<i;j++) {
                dp[i]=(dp[i]-dp[j]*solve(i,j)%mod+mod)%mod;
            }
        }
        printf("Case #%d: %I64d\n",++cas,(dp[k]%mod+mod)%mod);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值