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

  • 相关阅读:
    【Matlab】把一年中的某一天(从1月1日起)换算成日期
    【工具】用hexo搭建博客
    【工具】文献分析工具histcite的简单使用
    【工具】用PPT排版打印海报时图片分辨率问题
    【工具】PPT插入高清图片保存后图片变模糊的解决方法
    【工具】排版软件TeX Live 2016的简单使用
    【工具】文字识别软件(OCR) ABBYY Finereader 11简单使用
    【Matlab】编程风格摘录
    【信号】用matlab实现一维信号的高斯滤波
    【GMT5】用GMT绘制测高卫星Topex_Poseidon_Jason的地面轨迹
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9735626.html
Copyright © 2011-2022 走看看