zoukankan      html  css  js  c++  java
  • BZOJ1112

    原题链接

    题意简述

    给出一个n(n105)个数的序列a(max{a}106),每次给一个数+1/-1。求使得序列中存在连续k(kn)个相等的数至少要操作几次。

    分析

    题目实际上求的是|x1h|+|x2h|+...+|xkh|的最小值,其中xa的一个长度为k的子串。
    易知h为序列x的中位数时原式取得最小值,那我们的任务就是求区间中位数咯。

    证明

    记序列x中小于h的有c1个,大于h的有c2个。
    因为当h增大Δh,原式就增大Δh×c1Δh×c2
    所以当c1<c2时,h越大原式越小;c1>c2时,h越大原式越大。
    c1=c2时原式取得最小值,此时h为序列x的中位数。

    因为max{a}106可以开数组,我们用树状数组实现。
    维护x中小于等于i的数的个数cnt[i],小于等于i的数的和sum[i]。首先通过二分找出中位数h0,则原式的最小值为

    h0×cnt[i]sum[i]+h0×(kcnt[i])×(Σxisum[i])

    总时间复杂度约为O(nlog2max{a})

    实现

    开两个树状数组分别维护cnt[i],sum[i]

    代码

    //[POI2008]鐮栧潡Klo
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long lint;
    int const N=1e5+10;
    int const M=1e6+10;
    lint const INF=1LL<<62;
    int n,k,a[N];
    int maxH; lint s[N];
    lint tr[M],trs[M];
    void add(int x,int f)
    {
        int x1=x;
        while(x1<=maxH) tr[x1]+=f,x1+=x1&(-x1);
        x1=x;
        while(x1<=maxH) trs[x1]+=f*x,x1+=x1&(-x1);
    }
    lint sum1(int x)
    {
        lint res=0;
        while(x>0) res+=tr[x],x-=x&(-x);
        return res;
    }
    lint sum2(int x)
    {
        lint res=0;
        while(x>0) res+=trs[x],x-=x&(-x);
        return res;
    }
    lint sol(int fr)
    {
        int L=0,R=maxH;
        while(L<R)
        {
            int mid=(L+R)>>1;
            if(sum1(mid)<(k+1)/2) L=mid+1;
            else R=mid;
        }
        lint h=L,c1=sum1(h),c2=k-c1;
        lint s1=sum2(h),s2=s[fr+k-1]-s[fr-1]-s1;
        return (c1*h-s1)+(s2-c2*h);
    }
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]++;
        for(int i=1;i<=n;i++) maxH=max(maxH,a[i]);
        for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
        lint ans=INF;
        for(int i=1;i<=k;i++) add(a[i],1);
        ans=min(ans,sol(1));
        for(int i=2;i<=n-k+1;i++)
        {
            add(a[i-1],-1); add(a[i+k-1],1);
            ans=min(ans,sol(i));
        }
        printf("%lld",ans);
        return 0;
    }

    注意

    要开long long
    原数列中可能有0,先给全体+1s+1

  • 相关阅读:
    http缓存机制与原理
    BFC与浮动
    05ICMP协议与ARP协议(IP协议中重要协议)
    04IP编址(网络层)
    03以太网帧结构(链路层 IEEE802.3)
    02传输介质简介
    shell 脚本 2
    shell 脚本 1
    shell 中时间 表达
    sed 行编辑器
  • 原文地址:https://www.cnblogs.com/VisJiao/p/8485768.html
Copyright © 2011-2022 走看看