HDU 6333 Harvest of Apples (莫队算法)

hdu6333 给出n和m,求C(n,0)+C(n,1)+...+C(n,m)的值。

把结果定义为S(n,m),可以得到S(n,m) = S(n-1,m) + S(n-1,m-1),由此就有S(n,m) = S(n,m-1) + C(n,m) = 2*S(n-1,m) - C(n,m)。

也就是说根据S(n,m)我们可以在O(1)的时间里求出S(n-1,m),S(n,m-1),S(n+1,m),S(n,m+1),于是就可以用莫队算法来做了。

莫队算法解决的问题就是对于n个数的数列,有若干(l,r)的询问,查询区间的某些性质。如果对于(l,r),可以O(1)内转移到(l,r-1),(l,r+1),(l+1,r),(l-1,r),就可以离线地处理这些询问,通过适当地改变运算顺序,在更优的时间复杂度内完成所有查询。

莫队算法首先将序列分成sqrt(n)个块,对查询的区间排序的时候,如果左端点在同一块里面就按右端点升序排序,否则就按左端点排序。这样按顺序处理的区间的时候可以使得转换的次数相对较小。以及此题里转移并不是简单的加减,需要使用上面的两个式子。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
const int maxn = 100007;
const ll mod = 1000000007;

int t, pos[maxn];
ll ans[maxn], inv[maxn], fac[maxn];
struct node
{
    int n, m;
    int id;
}e[maxn];

bool cmp(node a, node b)
{
    if(pos[a.n] != pos[b.n]) return a.n < b.n;
    return a.m < b.m;
}

ll qpow(ll a, ll x)
{
    ll ans = 1;
    while(x)
    {
        if(x & 1)
            ans = (ans*a) % mod;
        a = a*a % mod;
        x >>= 1;
    }
    return ans;
}

void init()
{
    int tmp = sqrt(maxn);
    for(int i = 1;i < maxn;i++)
        pos[i] = (i - 1)/tmp;
    fac[0] = inv[0] = 1;
    fac[1] = inv[1] = 1;
    for(int i = 2;i < maxn;i++)
        fac[i] = (fac[i - 1]*i) % mod;
    for(int i = 2;i < maxn;i++)
        inv[i] = qpow(fac[i], mod - 2);
        //inv[i] = (inv[i + 1]*(i + 1)) % mod;
}

ll C(int n, int m)
{
    if(n <= 0 || m < 0 || n < m)
        return 0;
    if(m == 0 || n == m)
        return 1;
    return fac[n]*inv[m] % mod*inv[n - m] % mod;
}

int main()
{
    scanf("%d", &t);
    init();
    for(int i = 1;i <= t;i++)
    {
        scanf("%d%d", &e[i].n, &e[i].m);
        e[i].id = i;
    }
    sort(e + 1, e + t + 1, cmp);
    ll L = 1, R = 0;
    ll res = 1;
    for(int i = 1;i <= t;i++)
    {
        while(L < e[i].n) res = (res*2 - C(L++, R) + mod) % mod;
        while(L > e[i].n) res = ((res + C(--L, R))*inv[2]) % mod;
        while(R < e[i].m) res = (res + C(L, ++R)) % mod;
        while(R > e[i].m) res = (res - C(L, R--) + mod) % mod;
        ans[e[i].id] = res;
    }
    for(int i = 1;i <= t;i++)
        printf("%lld\n", ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/NPU_SXY/article/details/81435062
今日推荐