zoukankan      html  css  js  c++  java
  • 雅礼集训 Day1 T1 养花

    养花

    题目描述

    (C)在家种了(n)盆花,每盆花有一个艳丽度(a_i).

    在接下来的(m)天中,每天早晨他会从一段编号连续的花中选择一盆摆放在客厅, 并在晚上放回. 同时每天有特定的光照强度(k_i), 如果这一天里摆放在客厅的花艳丽度为(x), 则他能获得的喜悦度为(x mathrm{mod} k_i).

    他希望知道, 每一天他能获得的最大喜悦度是多少.

    输出输出格式

    输入格式

    数据第一行包含两个正整数(n,m).

    接下来一行(n)个正整数, 第(i)个数(a_i)表示第(i)盆花的艳丽度.

    接下来(m)行, 每行三个正整数(l_i,r_i,k_i), 表示选花区间和光照强度.

    输出格式

    输出(m)行, 每行一个整数, 表示最大喜悦度.

    说明

    对于(20\%)的数据,(n,mle 4000).

    对于(40\%)的数据,(n,mle 50000).

    对于另外(20\%)的数据,(a_ile 300).

    对于(100\%)的数据,(n,m,a_i,k_ile 10^5).


    区间询问 (a_i mod k) 的最大值

    如果分块搞得熟估计可以A掉吧,或者主席树敢瞎写之类的

    最开始想到一个垃圾的(nlognsqrt n)做法

    思路是(k le sqrt n)预处理线段树套分块,然后(logn)查询

    (k > sqrt n)时暴力在主席树上找,单次(sqrt n logn)

    40pts 都拿不到

    正解的做法是分块,对位置的分块

    设块大小为(S),每个块预处理出模所有(k)时的最值

    处理的技巧其实有点神奇,(f[i])表示当前块(i)这个值的位置前面一个值是多少

    然后枚举(k),枚举每个区间,用(f[i])更新

    对每个块的复杂度是(sum_{i=1}^n frac{n}{i})

    发现是调和级数,则为(nlnn)

    总复杂度:(O(n^2lnn/s+ms))

    (S=sqrt{nlnn}),得到复杂度(O(nsqrt{nlnn}))

    事实上上界比较满,常数也不小,你谷最慢点跑了1.5s(雅礼只开了1s,跑的真快emm


    Code:

    #include <cstdio>
    #include <cstring>
    const int N=1e5;
    const int S=1e3;
    const int M=1e2;
    int mx[M+2][N+10],n,m,a[N+10],f[N+10];
    int max(int x,int y){return x>y?x:y;}
    int min(int x,int y){return x<y?x:y;}
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",a+i);
        int num=(n-1)/S;
        for(int i=0;i<=num;i++)
        {
            memset(f,0,sizeof(f));
            int l=i*S+1,r=min(n,(i+1)*S);
            for(int j=l;j<=r;j++) f[a[j]]=a[j];
            for(int j=1;j<=N;j++) f[j]=max(f[j-1],f[j]);
            for(int j=1;j<=N;j++)
                for(int k=0;k<=N;k+=j) mx[i][j]=max(mx[i][j],f[min(k+j-1,N)]-k);
        }
        for(int l,r,k,i=1;i<=m;i++)
        {
            int ans=0;
            scanf("%d%d%d",&l,&r,&k);
            int ll=(l-1)/S,rr=(r-1)/S;
            for(int j=ll+1;j<rr;j++) ans=max(ans,mx[j][k]);
            for(int j=l;j<=min(r,(ll+1)*S);j++) ans=max(ans,a[j]%k);
            for(int j=max(l,rr*S+1);j<=r;j++) ans=max(ans,a[j]%k);
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    2018.10.1

  • 相关阅读:
    如何让一个浮动垂直居中:两种方式!带来效果~~~~~~
    rgba()和opacity之间的区别(面试题)
    常用浏览器内核!IE,Chrome ,Firefox,Safari,Opera 等内核
    有关Option.inSamplSize 和 Compress 图片压缩
    Android App 启动 Activity 创建解析
     (转)windows一台电脑添加多个git账号
    Handler向子线程发送数据
    Android Touch事件分发
    int 转十六进制
    JVM client模式和Server模式
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9735626.html
Copyright © 2011-2022 走看看