zoukankan      html  css  js  c++  java
  • HDU 6333.Problem B. Harvest of Apples-组合数C(n,0)到C(n,m)求和-组合数学(逆元)+莫队 ((2018 Multi-University Training Contest 4 1002))

     2018 Multi-University Training Contest 4

    6333.Problem B. Harvest of Apples

    题意很好懂,就是组合数求和sum_{i=0}^{m}C(n,i)

    官方题解:

    我来叨叨一些东西。

    这题肯定不能一个一个遍历求和,这样就上天了。。。

    解释一下官方题解的意思。

    为什么 sum(n,m)=2*sum(n-1,m)-c(n-1,m)。

    因为c(n,m)=c(n-1,m)+c(n-1,m-1),至于为什么成立,不懂的百度一下组合数和杨辉三角吧。。。

    sum(n,m)=c(n,0)+c(n-1,1)+c(n-1,0)+c(n-1,2)+c(n-1,1)+...+c(n-1,m)+c(n-1,m-1)//因为c(n,0)=c(n-1,0)==1

         =c(n-1,0)+c(n-1,0)+c(n-1,1)+c(n-1,1)+c(n-1,2)+c(n-1,2)+...+c(n-1,m-1)+c(n-1,m-1)+c(n-1,m)

              =2*sum(n-1,m)-c(n-1,m)

    OK,解释完了,然后怎么做呢?

    通过上面推出来的公式,我们就可以在O(1)的复杂度里由Sum(n,m)推出Sum(n-1,m),Sum(n+1,m),Sum(n,m-1),Sum(n,m+1)。这个就可以用莫队写了。

    关于莫队,具体的去看别人的博客,人家写的很好,我语文不好+懒,不想写。。。

    要注意莫队的时候,while里的判断条件是当前指针对应的值与要求得的数的大小的关系,while(N<que[i].n) res=(2*res-C(N++,M)+mod)%mod;就假设,我当前的指针对应的值为sum(n-1,m),我需要得到的结果为sum(n,m),当前的N为n-1,所以我需要用公式sum(n,m)=2*sum(n-1,m)-c(n-1,m),经过这个操作,N就变成n了(因为N++)。

    大体就这些,其他的就是关于组合数求解的东西了,这些代码里注释了。

    代码:

      1 //1002-6333-组合数C(n,0)到C(n,m)求和-组合数学+莫队
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<cstring>
      5 #include<algorithm>
      6 #include<bitset>
      7 #include<cassert>
      8 #include<cctype>
      9 #include<cmath>
     10 #include<cstdlib>
     11 #include<ctime>
     12 #include<deque>
     13 #include<iomanip>
     14 #include<list>
     15 #include<map>
     16 #include<queue>
     17 #include<set>
     18 #include<stack>
     19 #include<vector>
     20 using namespace std;
     21 typedef long long ll;
     22 
     23 const double PI=acos(-1.0);
     24 const double eps=1e-6;
     25 const ll mod=1e9+7;
     26 const int inf=0x3f3f3f3f;
     27 const int maxn=1e5+10;
     28 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     29 
     30 int pos[maxn];
     31 ll inv[maxn],f[maxn],ans[maxn];
     32 
     33 struct node{
     34     int n,m,id;
     35 
     36     bool operator <(const node &a) const{
     37         if(pos[n]!=pos[a.n]) return n<a.n;
     38         return m<a.m;
     39     }
     40 
     41 }que[maxn];
     42 /*
     43 关于逆元
     44 费马小定理:对于a和素数p,a^(p-1)恒等于1。
     45 逆元的定义:对于正整数a和m,如果有a*x恒等于1,那么把这个同余方程中x的最小正整数解叫做a模m的逆元。一般用欧几里得扩展来做:ax+by=1;称a和b互为逆元
     46 a^(p−1)=a^(p−2)∗a,所以有a^(p−2)∗a%p≡1,对比逆元的定义可得,a^(p−2)是a的逆元
     47 所以组合数预处理------>阶乘逆元,n!%mod/[(n-m)!%mod*m!%mod],设n!%mod为A,(n-m)!%mod的逆元为B,m!%mod的逆元为C,所以组合数c(n,m)%mod=A*B%mod*C%mod,就酱~
     48 */
     49 ll qpow(ll a,ll b)//快速幂a^b%mod
     50 {
     51     ll res=1;
     52     while(b){
     53         if(b&1) res=(res*a)%mod;
     54         a=(a*a)%mod;
     55         b>>=1;
     56     }
     57     return res;
     58 }
     59 
     60 void init()
     61 {
     62     f[1]=1;
     63     for(int i=2;i<maxn;i++)//预处理出来i!%mod,就是c(n,m)中n!%mod先预处理
     64         f[i]=(f[i-1]*i)%mod;
     65     for(int i=1;i<maxn;i++)
     66         inv[i]=qpow(f[i],mod-2);//inv中存的是逆元为a^(p-2)
     67 }
     68 
     69 ll C(int n,int m)//求C(n,m)
     70 {
     71     if(n<0||m<0||m>n) return 0;
     72     if(m==0||m==n) return 1;
     73     return f[n]*inv[n-m]%mod*inv[m]%mod;//就是A*B%mod*C%mod
     74 }
     75 
     76 ll res=1;
     77 
     78 int main()
     79 {
     80     init();
     81     int T;
     82     scanf("%d",&T);
     83     int block=(int)sqrt(maxn);
     84     for(int i=1;i<=maxn-1;i++)
     85         pos[i]=(i-1)/block;
     86     for(int i=1;i<=T;i++){
     87         scanf("%d%d",&que[i].n,&que[i].m);
     88         que[i].id=i;
     89     }
     90     sort(que+1,que+1+T);
     91     int N=1,M=0;
     92     for(int i=1;i<=T;i++){
     93         while(N<que[i].n) res=(2*res-C(N++,M)+mod)%mod;
     94         while(N>que[i].n) res=((res+C(--N,M))*inv[2])%mod;
     95         while(M<que[i].m) res=(res+C(N,++M))%mod;
     96         while(M>que[i].m) res=(res-C(N,M--)+mod)%mod;
     97         ans[que[i].id]=res;
     98     }
     99     for(int i=1;i<=T;i++){
    100         printf("%lld
    ",ans[i]);
    101     }
    102     return 0;
    103 }
  • 相关阅读:
    Power BI for Office 365(八)共享查询
    Power BI for Office 365(七) Power BI站点
    Power BI for Office 365(六)Power Map简介
    Power BI for Office 365(五)Power View第二部分
    Power BI for Office 365(四)Power View第一部分
    Power BI for Office 365(三)Power Pivot
    Power BI for Office 365(二)Power Query
    java 继承、重载、重写与多态
    Android 热修复方案Tinker(一) Application改造
    阿里最新热修复Sophix与QQ超级补丁和Tinker的实现与总结
  • 原文地址:https://www.cnblogs.com/ZERO-/p/9427107.html
Copyright © 2011-2022 走看看