zoukankan      html  css  js  c++  java
  • Harvest of Apples (HDU多校第四场 B) (HDU 6333 ) 莫队 + 组合数 + 逆元

    题意大致是有n个苹果,问你最多拿走m个苹果有多少种拿法。题目非常简单,就是求C(n,0)+...+C(n,m)的组合数的和,但是询问足足有1e5个,然后n,m都是1e5的范围,直接暴力的话肯定时间炸到奶奶都不认识了。当时想了好多好多,各种骚操作都想了一遍就是没想到居然是莫队....我用S(n,m)来记录C(n,0)+...+C(n,m)的和作为一个询问的答案

    由组合数公式C(n,m) = C(n-1,m-1)+C(n-1,m)可以推的下面的式子

    S(n,m) = S(n,m-1) + C(n,m);

    S(n,m) = S(n,m+1) - C(n,m+1);

    S(n,m) = 2*S(n-1)-C(n,m);

    S(n,m) = ( S(n+1, m) + C(n,m) ) / 2;

    这样发现居然是一个莫队的基本操作....然而只知道这几点也是不够的,因为组合数计算涉及到除法,所以得求逆元,还是阶乘的逆元,所以得先预处理出1~n的阶乘和它们的逆元,求逆元也是很耗时间的,但是我们可以通过递推一遍把阶乘的逆元求出来

    设f(x)为x的逆元
    那么 f(n!) = f( (n-1)!*n ) = f((n-1)!)*f(n);
    将f(n)除过来 f(n!)*f(f(n)) = f((n-1)!)
    因为x的逆元的逆元就是x本身,  因此得到公式f(n!)*n = f((n-1)!),这样我们只要求出最大的阶乘的逆元就可以从大到小推出所有逆元的值

    就酱(顺便说一句不知道为啥hdu选c++会TLE或者WA,得用G++编译)

      1 #include <iostream>
      2 #include <string.h>
      3 #include <cstdio>
      4 #include <vector>
      5 #include <queue>
      6 #include <stack>
      7 #include <math.h>
      8 #include <string>
      9 #include <algorithm>
     10 #include <functional>
     11 
     12 #define SIGMA_SIZE 26
     13 #define lson rt<<1
     14 #define rson rt<<1|1
     15 #define lowbit(x) (x&-x)
     16 #define foe(i, a, b) for(int i=a; i<=b; i++)
     17 #define fo(i, a, b) for(int i=a; i<b; i++)
     18 #define pii pair<int,int>
     19 #pragma warning ( disable : 4996 )
     20 
     21 using namespace std;
     22 typedef long long LL;
     23 inline double dMax(double a, double b) { return a>b ? a : b; }
     24 inline double dMin(double a, double b) { return a>b ? b : a; }
     25 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
     26 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
     27 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
     28 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
     29 inline int Max(int a, int b) { return a>b ? a : b; }
     30 inline int Min(int a, int b) { return a>b ? b : a; }
     31 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
     32 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
     33 const LL INF = 0x3f3f3f3f3f3f3f3f;
     34 const LL mod = 1e9+7;
     35 const double eps = 1e-8;
     36 const int inf = 0x3f3f3f3f;
     37 const int maxk = 3e6 + 5;
     38 const int maxn = 1e5+5;
     39 
     40 int n, m, unit;
     41 int belong[maxn];
     42 LL fac[maxn], inv[maxn],invof2;
     43 LL ans[maxn];
     44 struct node {
     45     int lhs, rhs, id;
     46 }pp[maxn];
     47 
     48 bool cmp(const node& a, const node& b)
     49 {
     50     if (belong[a.lhs] == belong[b.lhs]) 
     51         return (belong[a.lhs]&1) ? a.rhs<b.rhs : a.rhs>b.rhs;
     52     return a.lhs < b.lhs;
     53 }
     54 
     55 //设f(x)为x的逆元
     56 //f(n!) = f( (n-1)!*n ) = f((n-1)!)*f(n);
     57 //将f(n)除过来 f(n!)*f(f(n)) = f((n-1)!)
     58 //因此可以从最大的n反向推回小的
     59 LL getM( LL a, LL b, LL m)
     60 {
     61     LL ans = 1, base = a;
     62     while (b)
     63     {
     64         if ( b & 1 )
     65             ans = (ans*base) % m;
     66         base = (base*base) % m;
     67         b >>= 1;
     68     }
     69     return ans;
     70 }
     71 
     72 void init()
     73 {
     74     fac[0] = fac[1] = 1;
     75     inv[0] = inv[1] = 1;
     76     foe(i, 2, maxn)
     77         fac[i] = fac[i-1]*i%mod;
     78 
     79     inv[maxn-1] = getM(fac[maxn-1], mod-2, mod);
     80     invof2 = getM(2, mod-2, mod);
     81     for ( int i = maxn-2; i >= 2; i-- )
     82         inv[i] = (inv[i+1]*(i+1))%mod;
     83 }
     84 
     85 LL C(int down, int up)
     86 {
     87     if ( up > down ) return 0;
     88     return fac[down]*inv[up]%mod*inv[down-up]%mod;
     89 }
     90 
     91 int main()
     92 {
     93     init();
     94     int T;
     95     cin >> T;
     96     unit = sqrt(T);
     97 
     98     foe(i, 1, T)
     99     {
    100         scanf("%d %d", &n, &m);
    101         pp[i].lhs = n; pp[i].rhs = m;
    102         pp[i].id = i;
    103         belong[i] = i/unit+1;
    104     }
    105     sort(pp+1, pp+1+T, cmp);
    106 
    107     //(l代表n, r代表m)
    108     int l = 1, r = 0;
    109     LL sum = 1;
    110 
    111     for ( int i = 1; i <= T; i++ )
    112     {
    113         while (r < pp[i].rhs) {
    114             r++;
    115             sum = (sum + C(l, r))%mod;
    116         }
    117 
    118         while (r > pp[i].rhs) {
    119             sum = (sum - C(l, r)+mod)%mod;
    120             r--;
    121         }
    122 
    123         while (l < pp[i].lhs) {
    124             sum = ((LL)2*sum - C(l, r)+mod)%mod;
    125             l++;
    126         }
    127 
    128         while (l > pp[i].lhs) {
    129             l--;
    130             sum = (sum+C(l,r))%mod*invof2%mod;
    131         }
    132 
    133         ans[pp[i].id] = sum;
    134     }
    135 
    136     foe(i, 1, T)
    137         printf("%lld
    ", ans[i]);
    138     return 0;
    139 }
    View Code
  • 相关阅读:
    Shuffle Cards
    求和VII
    Finite Encyclopedia of Integer Sequences(找规律)
    Codeforces Round #223 (Div. 2) C
    Codeforces Round #223 (Div. 2) A
    题目1047:素数判定
    Codeforces Round #219 (Div. 1) C. Watching Fireworks is Fun
    Codeforces Round #219 (Div. 2) B. Making Sequences is Fun
    中南大学第一届长沙地区程序设计邀请赛 New Sorting Algorithm
    中南大学第一届长沙地区程序设计邀请赛 To Add Which?
  • 原文地址:https://www.cnblogs.com/chaoswr/p/9414608.html
Copyright © 2011-2022 走看看