zoukankan      html  css  js  c++  java
  • HDU 5794 A Simple Chess ——(Lucas + 容斥)

      网上找了很多人的博客,都看不太懂,还是大力学长的方法好。

      要说明的一点是,因为是比较大的数字的组合数再加上mod比较小,因此用Lucas定理求组合数。

      代码如下(有注释):

      1 #include <stdio.h>
      2 #include <algorithm>
      3 #include <string.h>
      4 #include <set>
      5 #include <vector>
      6 using namespace std;
      7 const int mod = 110119;
      8 typedef long long ll;
      9 typedef pair<ll,ll> pii;
     10 
     11 int k;
     12 ll fact[120000+5],dp[100+5];
     13 ll n,m;
     14 vector<pii> V;
     15 
     16 void init()
     17 {
     18     fact[0] = fact[1] = 1;
     19     for(int i=2;i<=120000;i++) fact[i] = fact[i-1] * i % mod;
     20 }
     21 
     22 void ex_gcd(ll a,ll b,ll &x,ll &y,ll &d)
     23 {
     24     if(!b) {d = a; x = 1; y = 0;}
     25     else
     26     {
     27         ex_gcd(b,a%b,y,x,d);
     28         y -= x * (a/b);
     29     }
     30 }
     31 
     32 ll qpow(ll a,ll b)
     33 {
     34     ll ans = 1;
     35     while(b)
     36     {
     37         if(b & 1) ans = ans * a % mod;
     38         a = a * a % mod;
     39         b >>= 1;
     40     }
     41     return ans;
     42 }
     43 
     44 ll inv(ll t,ll p)
     45 {
     46     /*ll x,y,d;
     47     ex_gcd(t,p,x,y,d);
     48     return d==1 ? (x%mod+mod)%mod : -1;*/
     49     return qpow(t,p-2);
     50 }
     51 
     52 int comb(int n,int m)
     53 {
     54     if(m<0 || n<m) return 0;
     55     return fact[n] * 1LL * inv(fact[m],mod) % mod * inv(fact[n-m],mod) % mod;
     56 }
     57 
     58 ll Lucas(ll n,ll m,int p)
     59 {
     60     return m ? Lucas(n/p,m/p,p) * comb(n%p,m%p) % mod : 1;
     61 }
     62 
     63 ll solve(int i,int j) // j to i 的无视障碍的步数总数
     64 {
     65     if(V[i].second < V[j].second || V[i].first < V[i].first || (V[i].first+V[i].second-V[j].first-V[j].second)%3) return -1;
     66     ll need = (V[i].first+V[i].second-V[j].first-V[j].second) / 3;
     67     // need 表示走过的步数
     68     ll step = Lucas(need, V[i].first-V[j].first-need, mod);
     69     // 第二个参数表示走过的两步的步数
     70     // 总的步数(need)中选择若干步是走两步的
     71     return step % mod;
     72 }
     73 
     74 int main()
     75 {
     76     init();
     77     int kase = 1;
     78     while(scanf("%I64d%I64d%d",&n,&m,&k)==3)
     79     {
     80         V.clear();
     81         for(int i=1;i<=k;i++)
     82         {
     83             ll x,y;scanf("%I64d%I64d",&x,&y);
     84             V.push_back(pii(x,y));
     85         }
     86         V.push_back(pii(1,1));
     87         V.push_back(pii(n,m));
     88         sort(V.begin(),V.end());
     89         memset(dp,0,sizeof(dp));
     90         int sz = V.size();
     91         for(int i=1;i<sz;i++)
     92         {
     93             dp[i] = solve(i,0);
     94             if(dp[i] == -1) dp[i] = 0;
     95             for(int j=0;j<i;j++)
     96             {
     97                 ll step = solve(i,j);
     98                 if(step != -1)
     99                 {
    100                     dp[i] -= step * dp[j] % mod;
    101                     // 所有从原点到i这个点的路径中,从原点到禁止点再从该禁止点到i点的所有路径都是不被允许的,需要减掉
    102                     if(dp[i] < 0) dp[i] = ((dp[i] % mod) + mod) % mod;
    103                 }
    104             }
    105         }
    106         printf("Case #%d: %I64d
    ",kase++,dp[sz-1]);
    107     }
    108 }
  • 相关阅读:
    Linux命令(九)——系统监视和进程控制
    Linux命令(八)——vi编辑器的使用
    Linux命令(七)——网络配置和网络通信
    Linux命令(六)——软件包管理(安装应用程序)
    Linux命令(五)——磁盘操作及文件系统的管理
    Linux命令(四)——文件权限管理
    Linux命令(三)——用户、群组管理命令
    Linux命令(二)——目录和文件管理命令
    mariadb读写分离
    KVM虚拟机热迁移
  • 原文地址:https://www.cnblogs.com/zzyDS/p/5796891.html
Copyright © 2011-2022 走看看