HDU - 6333 Harvest of Apples (莫队)

题目链接

题意:求出C(n,0)~C(n,m)的和,mod 1e9+7 。

分析:题目给的数据范围1<=n,m<=1e5,1<=T<=1e5,直接求出C(n,i)然后累加起来显然复杂度不行,在官方的题解中给出了如下的公式。
这里写图片描述

虽然在比赛中找出了这两个东西,但是看过的人那么多,一味的以为有直接用公式算出来的方法,所以一直在推公式,思维太局限,没有想到莫队。预处理阶乘和逆元,在双指针移动的时候能够O(1)的求出C(i,j);废话不多说,上代码。

#include 
#define mst(a,b) memset(a,b,sizeof(a))
#define ALL(x) x.begin(),x.end()
#define pii pair
#define eps 1e-8
inline int lowbit(int x){ return x & -x; }
const int N = 1e5+10;
const long long mod = (long long) 1e9 + 7;
const int INF = 0x3f3f3f3f;
const long long LINF = (1LL << 62);
typedef long long LL;
typedef unsigned long long ULL;
const double PI = acos(-1.0);
using namespace std;

LL C[N],inv[N],ans[N];
int bl[N];

struct Q{
  int n, m, id, No;  
  bool operator < (const Q &t) const{
    if(id != t.id) return id < t.id;  //对块排序,相同的块就按右区间小的排
    return m < t.m;
  }
}Q[N];
LL q_pow(LL base, LL b){
  LL res = 1;
  while(b){
    if(b&1) res = res * base % mod;
    base = base * base % mod;
    b >>= 1;
  }
  return res;
}
void init(){   //预处理阶乘和逆元
  C[0] = C[1] = 1;
  for(int i = 2; i <= 1e5; i++) C[i] = C[i - 1] * i % mod;
  inv[(int)1e5] = q_pow(C[(int)1e5], mod - 2);
  for(int i = 1e5 - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
}
inline LL get_C(int n, int m){
  return C[n] * inv[m] % mod * inv[n - m] % mod;
}

int main(){
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//    freopen("out.txt","w",stdout);
#else
//    freopen("caravan.in","r",stdin);
//    freopen("caravan.out","w",stdout);
#endif
    init();
    LL inv2 = q_pow(2, mod - 2);
    int blo = sqrt(1e5);
    for(int i = 1; i <= 1e5; i++) bl[i] = (i - 1) / blo + 1; //预处理每个数所在的块的编号
    int T; scanf("%d",&T);
    int n, m;
    for(int i = 1; i <= T; i++){
      scanf("%d%d",&Q[i].n,&Q[i].m);
      Q[i].No = i;
      Q[i].id = bl[Q[i].n];
    }
    sort(Q + 1, Q + 1 + T);
    int l = 0, r = 0;
    LL sum = 1;
    for(int i = 1; i <= T; i++){  //然后就是愉快的左右指针移动求答案了,下面就是公式所对应的东西。
      while(l < Q[i].n) sum = (sum + sum - get_C(l, r) + mod) % mod, l++;
      while(l > Q[i].n) sum = (sum + get_C(l - 1, r)) * inv2 % mod, l--;
      while(r < Q[i].m) sum = (sum + get_C(l, r + 1)) % mod, r++;
      while(r > Q[i].m) sum = (sum - get_C(l, r) + mod) % mod, r--;
      ans[Q[i].No] = sum;
    }
    for(int i = 1; i <= T; i++) printf("%I64d\n",ans[i]);
    return 0;
}

你可能感兴趣的:(莫队,思维)