zoukankan      html  css  js  c++  java
  • 【bzoj5177】[Jsoi2013]贪心的导游(分块)

      题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=5177

      在网上看到的题解基本都是用主席树,也就是带点骚操作的暴力直接艹过去的。这里分享一个比较清真的分块做法。

      因为$ p , a_i $的值域较小,因此我们可以考虑把序列分成$ size $块,预处理出每个块内的数模每个$ p $的最大值,那么查询时只需查询区间中的整块答案,然后再统计零散的元素的贡献。预处理时,我们可以考虑对当前块维护一个数组$ last[i] $表示在当前块内出现过的小于等于$ i $的最大的数,在计算模$ p $的答案时,因为$ f(x)=x mod p $是一个分段的单调函数,在$ [kp,(k+1)p-1] (k in mathbb{Z})$上单调递增,因此我们只需对每个区间$ [kp,(k+1)p-1] $求出区间内的最大值,也就是$ last[(k+1)p-1] $,作为模$ p $值最大的数。因此,每个块的预处理复杂度为$ O(1000 ln 1000) $。

      总时间复杂度为$ O(n+1000 ln 1000size+m(size+frac{n}{size})) $,当取$ size=sqrt{n} $时时间复杂度为$ 1000 ln 1000 sqrt{n}+msqrt{n}) approx 5.7 imes 10^7 $,比那些$ O(1000 m log n) $的做法清真到不知道哪里去了。

      代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<set>
    #define ll long long
    #define mod 1000000007
    #define Mod1(x) (x>=mod?x-mod:x)
    #define Mod2(x) (x<0?x+mod:x)
    #define maxn 1000010
    inline ll read()
    {
        ll x=0; char c=getchar(),f=1;
        for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
        for(;'0'<=c&&c<='9';c=getchar())x=x*10+c-'0';
        return x*f;
    }
    inline void write(ll x)
    {
        static int buf[20],len; len=0;
        if(x<0)x=-x,putchar('-');
        for(;x;x/=10)buf[len++]=x%10;
        if(!len)putchar('0');
        else while(len)putchar(buf[--len]+'0');
    }
    inline void writeln(ll x){write(x); putchar('
    ');}
    inline void writesp(ll x){write(x); putchar(' ');}
    int mx[1010][1010],last[1010];
    int a[maxn];
    int n,m,size;
    int main()
    {
        // freopen("bzoj5177.in","r",stdin);
        // freopen("bzoj5177.out","w",stdout);
        n=read(); m=read();
        for(int i=0;i<n;i++)
            a[i]=read();
        size=sqrt(n);
        // writeln(size);
        for(int k=0;k*size<n;k++){
            memset(last,0,sizeof(last));
            for(int i=k*size;i<(k+1)*size&&i<n;i++)
                last[a[i]]=a[i];
            for(int i=1;i<=1000;i++)
                if(!last[i])last[i]=last[i-1];
            for(int i=1;i<=1000;i++){
                for(int j=i;j<=1000;j+=i)
                    mx[k][i]=std::max(mx[k][i],last[j-1]-(j-i));
                mx[k][i]=std::max(mx[k][i],last[1000]%i);
            }
        }
        while(m--){
            int l=read(),r=read(),p=read();
            if(l>r){
                int tmp=l; l=r; r=tmp;
            }
            int idl=l/size,idr=r/size;
            if(idl==idr){
                int ans=0;
                for(int i=l;i<=r;i++)
                    ans=std::max(ans,a[i]%p);
                writeln(ans);
            }
            else{
                int ans=0;
                for(int i=idl+1;i<idr;i++)
                    ans=std::max(ans,mx[i][p]);
                for(int i=l;i<(idl+1)*size;i++)
                    ans=std::max(ans,a[i]%p);
                for(int i=idr*size;i<=r;i++)
                    ans=std::max(ans,a[i]%p);
                writeln(ans);
            }
        }
        // fclose(stdin); fclose(stdout);
        return 0;
    }
    bzoj5177
  • 相关阅读:
    cookie的使用
    给定一个数组和一个目标值,找出和为目标值的整数,并返回他们的下标
    String详解
    阳哥讲面试题(四)生产调优
    springboot项目调优(针对特性的服务启动,定制化诉求)
    intern() 方法
    阳哥讲面试题(四)OOM,GC算法,垃圾收集器
    阳哥讲面试题(三)JVM,GC
    阳哥讲面试题(二)队列,线程池
    Semaphore用法
  • 原文地址:https://www.cnblogs.com/quzhizhou/p/10685653.html
Copyright © 2011-2022 走看看