• NOIP 模拟 $12; ext{简单的区间}$


    题解

    签到题

    求区间和为 (k) 的倍数的区间,我们可以转化为求左右两个端点,其前缀和相等

    对于区间最大值,我们可以把其转化为一个值,它能向左,向右扩展的最远边界,一个单调栈即可

    我们设一个值 (i),它能扩展的左右边界分别为 (l_i,r_i) 那么我们将 (l_i~r_i) 分为两部分,(l_i~i)(i~r_i)

    枚举较小的那一段(可以证明总复杂度为 (mathcal O(nlogn)) ),在另一段寻找前缀和等于此前缀和加 (num_i) 的个数,用一颗动态开点线段树即可

    注意:此种做法边界要卡得很细致

    Code:
    #include<bits/stdc++.h>
    #define ri register signed
    #define p(i) ++i
    using namespace std;
    namespace IO{
        char buf[1<<21],*p1=buf,*p2=buf;
        #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++
        template<typename T>inline void read(T &x) {
            ri f=1;x=0;register char ch=gc();
            while(ch<'0'||ch>'9') {if (ch=='-') f=0;ch=gc();}
            while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
            x=f?x:-x;
        }
    }
    using IO::read;
    namespace nanfeng{
        #define cmax(x,y) ((x)>(y)?(x):(y))
        #define cmin(x,y) ((x)>(y)?(y):(x))
        #define FI FILE *IN
        #define FO FILE *OUT
        static const int N=3e5+7,K=1e6+1;
        int num[N],r[N],l[N],st[N],sum[N],nm[N],ans,tp,n,k;
        struct Segmenttree{
            #define ls(x) T[x].l
            #define rs(x) T[x].r
            #define up(x) T[x].nm=T[ls(x)].nm+T[rs(x)].nm
            struct seg{int l,r,nm;}T[K*20];
            int rt[K],tot;
            void update(int &x,int p,int l,int r) {
                if (!x) x=p(tot);
                if (l==r) {p(T[x].nm);return;}
                int mid(l+r>>1);
                if (p<=mid) update(ls(x),p,l,mid);
                else update(rs(x),p,mid+1,r);
                up(x);
            }
            int query(int x,int l,int r,int lt,int rt) {
                if (!x) return 0;
                if (l<=lt&&rt<=r) return T[x].nm;
                int mid(lt+rt>>1),res(0);
                if (l<=mid) res+=query(ls(x),l,r,lt,mid);
                if (r>mid) res+=query(rs(x),l,r,mid+1,rt);
                return res;
            }
        }T;
        inline int main() {
            // FI=freopen("nanfeng.in","r",stdin);
            // FO=freopen("nanfeng.out","w",stdout);
            read(n),read(k);
            for (ri i(1);i<=n;p(i)) {
                read(nm[i]);num[i]=nm[i]%k;
                sum[i]=(sum[i-1]+num[i])%k;
                T.update(T.rt[sum[i]],i,1,n);
                while(tp&&nm[st[tp]]<=nm[i]) r[st[tp--]]=i-1;
                l[i]=st[tp]+1;
                st[p(tp)]=i;
            }
            while(tp) r[st[tp--]]=n;
            for (ri i(1);i<=n;p(i)) {
                if (i==l[i]&&i==r[i]) continue;
                if (i-l[i]<=r[i]-i) {
                    for (ri j(l[i]);j<i;p(j)) 
                        ans+=T.query(T.rt[(sum[j-1]+num[i])%k],i,r[i],1,n);
                    if (i<r[i]) ans+=T.query(T.rt[sum[i]],i+1,r[i],1,n);
                } else {
                    for (ri j(i+1);j<=r[i];p(j)) 
                        if (l[i]-1) ans+=T.query(T.rt[(sum[j]-num[i]+k)%k],l[i]-1,i-1,1,n);
                        else {
                            ri tmp=(sum[j]-num[i]+k)%k;
                            ans+=T.query(T.rt[tmp],l[i],i-1,1,n);
                            if (!tmp) p(ans);
                        }
                    if (l[i]-1) ans+=T.query(T.rt[sum[i-1]],l[i]-1,i-2,1,n);
                    else {
                        if (i-2) ans+=T.query(T.rt[sum[i-1]],1,i-2,1,n);
                        if (!sum[i-1]) p(ans);
                    }
                }
            }
            printf("%d
    ",ans);
            return 0;
        } 
    }
    int main() {return nanfeng::main();}
    

    官方题解做法,为 (mathcal O(nlogn)) 复杂度较优,但其实没什么太大区别

    image

  • 相关阅读:
    逼哥
    作业
    malloc的底层实现
    docker基本使用
    对mudo中noncopyable类的理解
    整理
    替换war包中的文件
    SpringMVC(1):SpringMVC入门
    MySQL(5):安装MySQL
    MySQL(4):卸载MySQL
  • 原文地址:https://www.cnblogs.com/nanfeng-blog/p/15002437.html
Copyright © 2020-2023  润新知