[2018 Multi-University Training Contest 4] HDU 6333 Problem B. Harvest of Apples(莫隊算法)

題目鏈接

Problem B. Harvest of Apples

題目大意

T 組詢問, 每組詢問問i=0mCni .

數據範圍

1T105
1mn105

解題思路

定義S(n,m)=i=0mCni .
由楊輝三角的遞推公式Cnm=Cn1m1+Cn1m 可以推導出S(n,m)=2×S(n1,m)Cn1m

這樣我們就可以得到下面四個轉移公式:

S(n,m)=2×S(n1,m)Cn1mS(n,m)=S(n+1,m)+C(n,m)2S(n,m)=S(n,m1)+C(n,m)S(n,m)=S(n,m+1)C(n,m+1)

即使這樣可以O(1) 的轉移, 但是最壞也是需要O(n2) 的複雜度, 沒辦法實現。
這時候就可以把mn 看成區間lr 。 使用莫隊算法處理一下。 以前沒寫過莫隊, 正好趁這次機會學會了莫隊算法。

使用莫隊, 將n 分成n 塊, 按照l 所在的塊從小到大排序, 對於同一塊內, 按照r 從小到大排序。
這樣的話可以使複雜度降到O(nn)
簡單證明(現學現賣):

  1. 對於同一塊內, l 最多移動n , r 最多移動n 次,總共有n 塊, 所以這種情況的複雜度爲O(nn)
  2. 對不在同一塊內的, l 最多移動2×n 次, r 還是移動n 次, 所以還是O(nn)

AC代碼

/********************************************
 *Author*        :ZZZZone
 *Created Time*  : 日  8/ 5 14:48:44 2018
 * Ended  Time*  : 日  8/ 5 15:24:14 2018
 * 莫隊算法
*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define debug(x) std::cerr << #x << " = " << (x) << std::endl
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;

inline void OPEN(string s){
    freopen((s + ".in").c_str(), "r", stdin);
    freopen((s + ".out").c_str(), "w", stdout);
}

const int MAXN = 1e5;
const int Mod = 1e9 + 7;
LL fac[MAXN+5], rfac[MAXN+5], Ans[MAXN+5];
int blk[MAXN+5];
int n, Block;

struct Query{
    int l, r, id;
    bool operator < (const Query& tmp) const{
        if(blk[l] == blk[tmp.l]) return r < tmp.r;
        return blk[l] < blk[tmp.l];
    }
}Q[MAXN+5];

LL fast_pow(LL x, LL y){
    LL res = 1LL;
    while(y != 0LL){
        if(y & 1) res = (res * x) % Mod;
        y >>= 1;
        x = x * x % Mod;
    }
    return res;
}

inline LL Comb(LL N, LL M){
    if(N<M)return 0LL; //  ******  一定不能忘  ******   //
    return fac[N] * rfac[M] % Mod * rfac[N-M] % Mod;
}

void Init(){
    fac[0] = 1LL;
    for(int i = 1; i <= MAXN; i++) fac[i] = fac[i-1] * (LL)i % Mod;
    for(int i = 0; i <= MAXN; i++){
        rfac[i] = fast_pow(fac[i], Mod - 2LL);
        blk[i] = i / Block;
    }
    for(int i = 1; i <= n; i++) scanf("%d %d", &Q[i].r, &Q[i].l), Q[i].id = i;
    sort(Q + 1, Q + 1 + n);
}

int main()
{
    scanf("%d", &n);
    Block = sqrt(n);
    Init();
    int L = 1, R = 0;
    LL ans = 1LL;
    for(int i = 1; i <= n; i++){
        while(L < Q[i].l){
            L++;
            ans = (ans + Comb(R, L)) % Mod;
        }
        while(L > Q[i].l){
            ans = (ans - Comb(R, L) + Mod) % Mod;
            L--;
        }
        while(R < Q[i].r){
            ans = (2LL * ans % Mod - Comb(R, L) + Mod) % Mod;
            R++;
        }
        while(R > Q[i].r){
            R--;
            ans = (ans + Comb(R, L)) % Mod * rfac[2] % Mod;
        }
        Ans[Q[i].id] = ans % Mod;
    }
    for(int i = 1; i <= n; i++) printf("%lld\n", Ans[i]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章