HDU-5794 <2016 Multi-University Training 6> A Simple Chess (Lucas + DP)

来源:互联网 发布:滑坡效应 知乎 编辑:程序博客网 时间:2024/06/08 07:56

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

可以储存所有的点,再以从上到下,从左至右的顺序进行排序。

对于每个点i,有dp[i] = dp[i] - sum(dp[j]*Lucas(point[j]))  (0 <= j < i)

因此可以得到所有的点,对于不包括前i个点的路线数目。

那么答案ans = sum(dp[i]) (0 <= i < r)。

最后注意要对无影响的点进行去重。

#include <bits/stdc++.h>using namespace std;typedef long long LL;const LL p = 110119;struct Point{    LL x, y;    bool operator < (const Point &A) const{        if(x == A.x)            return y < A.y;        return x < A.x;    }}point[110];LL dp[110];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[110219];LL Get_Fact(LL p)  {      fac[0]=1;      for(int 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]%p)*PowMod(fac[b]*fac[a-b]%p,p-2,p))%p;          n/=p;          m/=p;      }      return ret;  }bool check(LL x, LL y){    if((x+y-2)%3 != 0)        return false;    if(min(x, y) > (x+y)/3)        return true;    return false;}int main(){    int r, cnt, CASE = 0;    LL n, m, x, y;    Get_Fact(p);    while(cin >> n >> m >> r){        cnt = 0;        for(int i = 0; i < r; i++){            scanf("%I64d %I64d", &x, &y);            if(check(x, y)){                point[cnt].x = x;                point[cnt++].y = y;                    }        }        if(!check(n, m) || (point[cnt-1].x == n && point[cnt-1].y == m)){            printf("Case #%d: 0\n", ++CASE);            continue;        }        sort(point, point + cnt);        point[cnt].x = n;        point[cnt].y = m;        for(int i = 0; i <= cnt; i++){            LL u = (LL)((point[i].x+point[i].y-2)/3);            LL v = (LL)((2*point[i].x-point[i].y-1)/3);            dp[i] = Lucas(u, v, p);            for(int j = 0; j < i; j++){                if(point[i].x >= point[j].x && point[i].y >= point[j].y){                    x = point[i].x-point[j].x+1;                    y = point[i].y-point[j].y+1;                    if(!check(x, y))                        continue;                    u = (LL)((x+y-2)/3);                    v = (LL)((2*x-y-1)/3);                    dp[i] -= (dp[j]*Lucas(u, v, p)%p);                    dp[i] = (dp[i]+p)%p;                }            }        }        printf("Case #%d: %I64d\n", ++CASE, dp[cnt]);    }    return 0;}


1 0