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\n", ans[i]);
138     return 0;
139 }
View Code

 

posted @ 2018-08-03 15:56  LBNOQYX  阅读(161)  评论(0编辑  收藏  举报