zoukankan      html  css  js  c++  java
  • HDU6333 求组合数前m项的和

    @


    HDU6333:传送门

    题意:求组合数前m项的和。
    在线分块or离线莫队

    分块

    重要的一个定理:

    [C_{n}^{m} = 0;;m > n ]

    [C_{n}^{m} = C_{a}^{0} imes C_{b}^{m}+C_{a}^{1} imes C_{b}^{m-1}...+C_{a}^{m} imes C_{b}^{0};;;a+b = n ]

    [ans = sum_{i=0}^m C_n^i=sum_{i=0}^m(C_a^i imes sum_{j=0}^{m-i} C_b^j);;a+b=n ]

    然后分块处理,b为整块的大小,块内枚举i求解。

    #include<bits/stdc++.h>
    #define lson rt<<1
    #define rson rt<<1|1
    #define all(x) (x).begin(),(x).end()
    #define mme(a,b) memset((a),(b),sizeof((a)))
    #define fuck(x) cout<<"* "<<x<<"
    "
    #define iis std::ios::sync_with_stdio(false)
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int MXN = 1e5 + 7;
    const int MXE = 1e6 + 7;
    const int INF = 0x3f3f3f3f;
    const LL MOD = 1e9 + 7;
    const LL mod = 1e9 + 7;
    
    int n;
    LL l, r;
    
    const int MX = 1e5 + 7;
    LL F[MX], invF[MX];
    LL ksm(LL a, LL b){
      LL res = 1;
      for(;b;b>>=1,a=a*a%mod){
        if(b&1)res = res * a % mod;
      }
      return res;
    }
    void init() {
      F[0] = 1;
      for (int i = 1; i < MX; i++) F[i] = F[i - 1] * i % mod;
      invF[MX - 1] = ksm(F[MX - 1], mod - 2);
      for (int i = MX - 2; i >= 0; i--) invF[i] = invF[i + 1] * (i + 1) % mod;
    }
    LL COMB(int n, int m) {
      if(n == m)return 1;
      if(n < m) return 0;
      return F[n]*invF[m]%mod*invF[n-m]%mod;
    }
    
    LL bpre[505][MXN];//bpre[i][j] = sigma(COMB(500*i,k)), k从[0, j]
    int blocks = 500;
    void yuchuli(){
      for(int i = 1; i < MXN/blocks; ++i){
        for(int j = 0; j < MXN; ++j){
          if(j==0)bpre[i][j] = COMB(blocks*i, j);
          else bpre[i][j] = (bpre[i][j-1] + COMB(blocks*i, j))%MOD;
        }
      }
    }
    
    int main(int argc, char const *argv[]){
    #ifndef ONLINE_JUDGE
        freopen("E://ADpan//in.in", "r", stdin);
        //freopen("E://ADpan//out.out", "w", stdout);  
    #endif
      init();
      yuchuli();
      int tim = 1;
      scanf("%d", &tim);
      while(tim--){
        scanf("%lld%lld", &r, &l);
        LL p = r/blocks, re = r - p * blocks, ans = 0;
        LL tmp = min(l, re), limit = p*500;
        //printf("%lld %lld
    ", p, re);
        if(p == 0) p = 1, limit = 0;
        for(int i = 0; i <= tmp; ++i){
          ans = (ans + COMB(re, i)*bpre[p][min(l-i, limit)])%MOD;
        }
        printf("%lld
    ", ans);
      }
      return 0;
    }
    

    莫队

    (S_n^m=sum C_n^m=Cn^0+Cn^1...+Cn^m)

    (S_n^{m-1}=sum C_n^{m-1}=Cn^0+Cn^1...+Cn^{m-1}=S_n^m-C_n^m)
    (S_n^{m+1}=sum C_n^{m+1}=Cn^0+Cn^1...+Cn^{m+1}=S_n^m+C_n^{m+1})
    (S_{n-1}^m=sum C_{n-1}^m=C_{n-1}^0+C_{n-1}^1...+C_{n-1}^m=(S_n^m+C_{n-1}^m)div 2)
    (S_{n+1}^m=sum C_{n+1}^m=C_{n+1}^0+C_{n+1}^1...+C_{n+1}^m =C_{n}^0+(C_{n}^0+C_n^1)+...+(C_n^{m-1}+C_n^m) =2 imes S_n^m-C_n^m)

    若已知S(m,n),则可在O(1)的时间内得到S(m-1,n),S(m+1,n),S(m,n-1),S(m,n+1),莫队即可。

    #include<bits/stdc++.h>
    #define lson rt<<1
    #define rson rt<<1|1
    #define fi first
    #define se second
    #define all(x) (x).begin(),(x).end()
    #define lowbit(x) (x&(-(x)))
    #define mme(a,b) memset((a),(b),sizeof((a)))
    #define test printf("**-**
    ")
    #define fuck(x) cout<<"* "<<x<<"
    "
    #define iis std::ios::sync_with_stdio(false)
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int MXN = 2e5 + 7;
    const int MXE = 1e6 + 7;
    const int INF = 0x3f3f3f3f;
    const LL mod = 1e9 + 7;
    
    int n;
    
    const int MX = 1e5 + 5;
    LL F[MX], invF[MX];
    LL ksm(LL a, LL b){
      LL res = 1;
      for(;b;b>>=1,a=a*a%mod){
        if(b&1)res = res * a % mod;
      }
      return res;
    }
    void init() {
      F[0] = 1;
      for (int i = 1; i < MX; i++) F[i] = F[i - 1] * i % mod;
      invF[MX - 1] = ksm(F[MX - 1], mod - 2);
      for (int i = MX - 2; i >= 0; --i) invF[i] = invF[i + 1] * (i + 1) % mod;
    }
    LL COMB(LL n, LL m) {
      if(n == m)return 1;
      if(n < m) return 0;
      return F[n]*invF[m]%mod*invF[n-m]%mod;
    }
    
    struct lp{
      int l, r, id;
    }cw[MX];
    int belong[MX];
    LL ans, Ans[MX];
    bool cmp(lp &a,lp &b){
      if(belong[a.l]!=belong[b.l])return belong[a.l]<belong[b.l];
      return a.r<b.r;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("E://ADpan//in.in", "r", stdin);
        //freopen("E://ADpan//out.out", "w", stdout);  
    #endif
      init();
      scanf("%d", &n);
      int block = sqrt(MX*1.0);
      for(int i = 1; i < MX; ++i)belong[i] = (i-1)/block;
      for(int i = 1; i <= n; ++i){
        scanf("%d%d", &cw[i].r, &cw[i].l);
        cw[i].id = i;
      }
      sort(cw+1,cw+n+1,cmp);
      int L = 1, R = 0;
      ans = 1LL;
      LL two = ksm(2LL, mod-2);
      for(int i = 1; i <= n; ++i){
        while(R<cw[i].r)ans = ((ans * 2LL - COMB(R++, L))%mod+mod)%mod ;
        while(R>cw[i].r)ans = (ans + COMB(--R, L))*two%mod ;
        while(L<cw[i].l)ans = (ans + COMB(R,++L))%mod ;
        while(L>cw[i].l)ans = (ans - COMB(R,L--) + mod)%mod ;
        Ans[cw[i].id] = ans;
      }
      for(int i = 1; i <= n; ++i){
        printf("%lld
    ", Ans[i]);
      }
      return 0;
    }
    

    在这里插入图片描述

  • 相关阅读:
    Rocket
    Rocket
    Rocket
    Rocket
    POJ 1849 树的直径 Two
    SGU 495 Kids and Prizes
    HDU 4336 概率DP 状压
    HDU 4089 && UVa 1498 Activation 带环的概率DP
    SGU 149 树形DP Computer Network
    暑假集训刷题记录
  • 原文地址:https://www.cnblogs.com/Cwolf9/p/10058297.html
Copyright © 2011-2022 走看看