HDU 6333 Harvest of Apples(莫队算法)

这道题一开始以为是lucas,然后就tle,赛后知道是莫队算法的时候还愣住了,刚才参考了别人的思路才知道这个状态可以推出关系的,通过左右状态的转变,离线化分块操作到达极低的时间复杂度,不仅对莫队算法认识加深了,也是复习了一下逆元,思路在下图中给出,代码就是普通的莫队

另外附上别人总结的莫队适用场合,认真思考以实现问题转化

①题目必须离线

②能够以极少的时间推出旁边区间(一般是O(1))

③没有修改或者修改不太苛刻

④基于分块,分块不行,它也好不了哪里去(何况现在还有可持久化数据结构维护的分块)

但莫队的思想美妙,代码优美,你值得拥有。莫队的排序思想也为众多离线处理的题目提供了完整的思路。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
#define maxn 100005
#define p 1000000007
long long fac[maxn];
long long inv[maxn];//逆元的阶乘
long long inv1[maxn];//逆元
long long ans[maxn];
struct node
{
    int l, r;
    int id;
    int block;
}a[maxn];
bool cmp(node a, node b)
{
    return a.block == b.block ? a.r < b.r : a.l < b.l;
}
void init()
{
    fac[0] = fac[1] = 1;
    inv1[0] = inv1[1] = 1;
    inv[0] = inv[1] = 1;
    for(int i = 2; i < maxn; i ++)
    {
        fac[i] = i * fac[i-1] % p;
        inv1[i] = (p-p/i)*inv1[p%i]%p;
        inv[i] = inv[i-1]*inv1[i]%p;
    }
}
long long c(int r, int l)
{
    return r < l ? 0 : fac[r]*inv[l]%p*inv[r-l]%p;
}
int main()
{
    int unit = sqrt(maxn);
    init();
    int n;
    int l = 1, r = 1;
    scanf("%d",&n);
    for(int i = 1; i <= n; i ++)
    {
        scanf("%d%d",&a[i].r,&a[i].l);
        a[i].id = i;
        a[i].block = a[i].l/unit;
    }
    sort(a + 1, a + 1 + n, cmp);
    long long ans1 = 2;
    for(int i = 1; i <= n; i ++)
    {
        while(l < a[i].l){ans1=(ans1+c(r,l+1))%p;l++;}
        while(l > a[i].l){ans1=(ans1-c(r,l)+p)%p;l--;}
        while(r > a[i].r){ans1=(ans1+c(r-1,l))*inv1[2]%p;r--;}
        while(r < a[i].r){ans1=(2*ans1-c(r,l)+p)%p;r++;}
        ans[a[i].id] = ans1;
    }
    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、付费专栏及课程。

余额充值