zoukankan      html  css  js  c++  java
  • 【时光回溯】【JZOJ3568】【GDKOI2014】小纪的作业题

    题目描述

    这里写图片描述

    输入

    这里写图片描述

    输出

    有M行,每个询问一行,输出结果mod 1,000,000,007的值。

    样例输入

    10 3
    3 5 1 2 3 1 3 5 2 1
    7 9
    3 9
    2 3

    样例输出

    10
    19
    6

    数据范围

    对于30%的数据,N,M<=1000
    对于50%的数据,N,M<=30000
    对于100%的数据,N,M<=100000

    解法

    离线不修改区间询问,考虑莫队算法。
    利用线性筛法预处理出所有要用的逆元后。
    显然每次容易O(1)处理。
    总的时间复杂度为O(n1.5)

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    #define sqr(x) ((x)*(x))
    #define ln(x,y) ll(log(x)/log(y))
    using namespace std;
    const char* fin="ex3568.in";
    const char* fout="ex3568.out";
    const ll inf=0x7fffffff;
    const ll maxn=100007,mo=1000000007;
    ll n,m,i,j,k,ks,l,r,tmp;
    ll a[maxn],ans[maxn],tong[maxn],tx[maxn];
    ll ny[maxn];
    struct qu{
        ll l,r,lk,id;
    }b[maxn];
    bool cmp(qu a,qu b){
        return a.lk<b.lk || a.lk==b.lk && a.r<b.r;
    }
    ll qpower(ll a,ll b){
        ll c=1;
        while (b){
            if (b&1) c=c*a%mo;
            a=a*a%mo;
            b>>=1;
        }
        return c;
    }
    void add(ll v){
        tmp=(tmp+mo-tx[a[v]])%mo;
        if (tong[a[v]]==0) tx[a[v]]=1;
        tong[a[v]]++;
        tx[a[v]]=(tx[a[v]]*a[v])%mo;
        tmp=(tmp+tx[a[v]])%mo;
    }
    void del(ll v){
        tmp=(tmp+mo-tx[a[v]])%mo;
        tong[a[v]]--;
        tx[a[v]]=(tx[a[v]]*ny[a[v]])%mo;
        if (tong[a[v]]==0) tx[a[v]]=0;
        tmp=(tmp+tx[a[v]])%mo;
    }
    int main(){
        scanf("%d%d",&n,&m);
        ks=(ll)(sqrt(n));
        for (i=1;i<=n;i++) scanf("%d",&a[i]);
        for (i=1;i<=100000;i++) ny[i]=qpower(i,mo-2);
        for (i=1;i<=m;i++){
            scanf("%d%d",&b[i].l,&b[i].r);
            b[i].lk=(b[i].l-1)/ks+1;
            b[i].id=i;
        }
        sort(b+1,b+m+1,cmp);
        l=1;
        r=0;
        tmp=0;
        for (i=1;i<=m;i++){
            while (r<b[i].r) add(++r);
            while (l>b[i].l) add(--l);
            while (l<b[i].l) del(l++);
            while (r>b[i].r) del(r--);
            ans[b[i].id]=tmp;
        }
        for (i=1;i<=m;i++) printf("%lld
    ",ans[i]);
        return 0;
    }

    启发

    涉及到预处理素数取模时的逆元,可由这道题对线筛的分析得到预处理逆元的可能性。


    莫队的单次扩展一定要保证O(1)的时间。

  • 相关阅读:
    【数论】X problem
    【数论】约瑟夫问题
    【组合数学】购票问题
    【组合数学】计数原理
    spring batch批处理框架学习
    eclipse自动添加javadoc注释
    eclipse手动安装alibaba代码规范插件
    现代支付系统的资金流向
    利用网易有道在谷歌浏览器进行网页滑词翻译
    spring配置遇到的问题
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714871.html
Copyright © 2011-2022 走看看