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

该博客介绍了如何利用莫队算法解决HDU 6333题目中关于苹果收获的问题。通过将数据范围和解题思路进行分析,提出将m和n视为区间,应用莫队算法将时间复杂度降低到O(n*sqrt(n))。博主分享了首次使用莫队算法的心得,并提供了AC代码。
摘要由CSDN通过智能技术生成

题目链接

Problem B. Harvest of Apples

题目大意

T T 组询问, 每组询问问i=0mCni.

数据范围

1T105 1 ≤ T ≤ 10 5
1mn105 1 ≤ m ≤ n ≤ 10 5

解题思路

定义 S(n,m)=mi=0Cin S ( n , m ) = ∑ i = 0 m C n i .
由杨辉三角的递推公式 Cmn=Cm1n1+Cmn1 C n m = C n − 1 m − 1 + C n − 1 m 可以推导出 S(n,m)=2×S(n1,m)Cmn1 S ( n , m ) = 2 × S ( n − 1 , m ) − C n − 1 m

这样我们就可以得到下面四个转移公式:

S(n,m)=2×S(n1,m)Cmn1S(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) S ( n , m ) = 2 × S ( n − 1 , m ) − C n − 1 m S ( n , m ) = S ( n + 1 , m ) + C ( n , m ) 2 S ( n , m ) = S ( n , m − 1 ) + C ( n , m ) S ( n , m ) = S ( n , m + 1 ) − C ( n , m + 1 )

即使这样可以 O(1) O ( 1 ) 的转移, 但是最坏也是需要 O(n2) O ( n 2 ) 的复杂度, 没办法实现。
这时候就可以把 m m n看成区间 l l r。 使用莫队算法处理一下。 以前没写过莫队, 正好趁这次机会学会了莫队算法。

使用莫队, 将 n n 分成n块, 按照 l l 所在的块从小到大排序, 对于同一块内, 按照r从小到大排序。
这样的话可以使复杂度降到 O(nn) O ( n ∗ n )
简单证明(现学现卖):

  1. 对于同一块内, l l 最多移动n, r r 最多移动n次,总共有 n n 块, 所以这种情况的复杂度为 O(nn) O ( n ∗ n )
  2. 对不在同一块内的, l l 最多移动2×n次, r r 还是移动n次, 所以还是 O(nn) O ( n ∗ n )

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值