HDU 5794 - A Simple Chess

HDU 5794 - A Simple Chess
题意:

  马(象棋)初始位置在(1,1), 现在要走到(n,m), 问有几种走法

  棋盘上有r个障碍物, 该位置不能走, 并规定只能走右下方

  

  数据范围: ( 1 ≤ n,m ≤10^18, 0 ≤ r ≤100 )
    
分析:

  分析不存在障碍物时的走法规律:
    
                 (1,1)                      1
              (2,3) (3,2)                      1   1
           (3,5) (4,4) (5,3)              1   2   1
        (4,7) (5,6) (6,5) (7,4)       1   3   3   1
                ......               ......
        发现走法规律是一个斜着的杨辉三角, 即i层第j个的走法数为: C[i,j-1] (组合数)

 

   那么根据换算, 层数 = (x+y+1)/3 - 1 , 个数 = x - (x+y+1)/3

   即可得到无障碍物时,(m,n)点的路径数
    
    
    分析障碍物的贡献与障碍物之间的相互影响:

    障碍物(x,y)的贡献 = (1,1)到(x,y)的路径数 * (x,y)到(n,m)的路径数, 后者通过相对位置(平移)计算

    障碍物之间的影响, 即应去掉的重复部分, 也如此计算
    
        
    因为n,m数据范围大, 故计算组合数应用 LUCAS定理

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 using namespace std;
  6 #define LL long long
  7 const LL MOD = 110119;
  8 long long fac[MOD];
  9 //求a^n % MOD的值
 10 template<class T1, class T2>
 11 T1 QuickPow(T1 x, T2 n, T1 MOD) 
 12 {  
 13     T1 ans = 1;
 14     while (n) 
 15     {  
 16         if (n & 1) ans = (ans * x) % MOD;
 17         x = (x * x) % MOD;
 18         n >>= 1;
 19     }  
 20     return ans;  
 21 }
 22 //组合数
 23 //参数为C(n, m) % p (p为质数)
 24 //fac[i]表示i! % p
 25 template<class T, class Type>
 26 T C(Type n, Type m, T p) 
 27 {
 28     if (n < m) return 0;
 29     T x = fac[n], y = fac[n-m] * fac[m] % p;
 30     return x * QuickPow(y, p - 2, p) % p;
 31 }
 32 //生成i! % p (i = 0->p-1)
 33 //配合Lucas定理使用
 34 template<class T>
 35 void ProFac(T *fac, T p) 
 36 {
 37     fac[0] = 1;
 38     for (int i = 1; i < (int)p; i++)
 39         fac[i] = fac[i-1] * i % p;
 40 }
 41 //Lucas定理
 42 //求C(n, m) % p (n, m可以很大, p最大可为1e5, p为质数)
 43 //后面两个参数内部使用,不必考虑
 44 template<class T>
 45 T Lucas(T n, T m, T p) 
 46 {
 47     if (m == 0)  return 1LL;
 48     else 
 49     {
 50         T res = C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
 51         return res;
 52     }
 53 }
 54 
 55 
 56 inline bool change(LL x,LL y, LL &m,LL &n) //将(x,y) 转为 C[b][a]
 57 {
 58     if((x + y + 1) % 3 != 0 ) return 0;
 59     LL a = (x + y + 1) / 3;
 60     if(x < a || y < a) return 0;
 61     m = x - a;
 62     n = a - 1;
 63     return 1;
 64 }
 65 
 66 struct CC
 67 {
 68     LL x, y, a, b;
 69 }g[105];
 70 LL n, m, a, b;
 71 int r, tot;
 72 LL gx[105], gy[105], val[105];
 73 LL ans;
 74 
 75 bool cmp(CC a, CC b) 
 76 {
 77     return a.b < b.b;
 78 }
 79 bool flag;
 80 int main()
 81 {
 82     ProFac(fac, MOD);
 83     int tt = 1;
 84     while (~scanf("%lld%lld%d",&n,&m,&r))
 85     {
 86         flag = 0;
 87         for (int i = 1; i <= r; i++)
 88         {
 89             scanf("%lld%lld", &gx[i], &gy[i]);
 90             if(gx[i] == n && gy[i] == m) flag = 1;
 91         }
 92         printf("Case #%d: ", tt++);
 93         if (flag || !change(n, m, a, b)) //障碍物在 n,m 点,或者不能跳到n,m 
 94         {
 95             puts("0"); continue;
 96         }
 97         tot = 0;
 98         for (int i = 1; i <= r; i++)
 99         {
100             if (!change(n - gx[i] + 1,m - gy[i] + 1, g[tot].a, g[tot].b)) continue; //该位置不能影响到 n,m点 
101             if (change(gx[i], gy[i], g[tot].a, g[tot].b)) // 有效障碍物点
102             {
103                 g[tot].x = gx[i], g[tot].y = gy[i];
104                 tot++;
105             }
106         }
107         ans = Lucas(b, a, MOD);//C[b][a]
108         sort(g, g + tot, cmp);
109         for (int i = 0; i < tot; i++)
110         {
111             val[i] = Lucas(g[i].b, g[i].a, MOD);//到每个障碍物的的路径数 
112         }
113         for (int i = 0; i < tot; i++)
114         {
115             LL a1, b1, tmp;
116              if (!change(n - g[i].x + 1, m - g[i].y + 1, a1, b1) ) continue;
117             tmp = Lucas(b1, a1, MOD);
118             ans = (ans + MOD - (val[i] * tmp % MOD )) % MOD;//减去障碍物贡献 
119             for (int j = i + 1; j < tot; j++)
120             {
121                 if ( !change(g[j].x - g[i].x + 1, g[j].y - g[i].y + 1, a1, b1) ) continue;
122                 tmp = Lucas(b1, a1, MOD);
123                 val[j] = (val[j] + MOD - (val[i] * tmp % MOD )) % MOD; //减去障碍物之间的影响 
124             }
125         }
126         printf("%lld\n", ans);
127     }
128 }

 

转载于:https://www.cnblogs.com/nicetomeetu/p/5741800.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值