P6958 [NEERC2017]The Great Wall

题意:

戳这里

分析:

首先由于 \(k\) 很大,所以我们没有办法直接求出第 \(k\) 个值,所以我们考虑二分答案,检验它是不是第 \(k\) 个

那么我们考虑如何 \(check\) ,首先方案选择分为两种情况,为了方便起见,我们令 \(c_i=c_i-a_i,b_i=b_i-a_i\) ,这样 \(a\) 相当于是必选的,然后我们维护三个序列的前缀和

  1. 两个区间不相交

    \[sum=b_{x+r-1}-b_{x-1}+b_{y+r-1}-b_{y-1} \\ =(b_{x+r-1}-b_{x-1})+(b_{y+r-1}-b_{y-1}) \\ =g(x)+g(y) \]

    我们枚举 \(y\) 查询一下 \([1,y-r]\) 中满足 \(g(y)+g(x)\le mid\) 的 \(x\) 个数,二维数点问题直接树状数组

  2. 两个区间相交

    \[sum=b_{y-1}-b_{x-1}+c_{x+r-1}-c_{y-1}+b_{y+r-1}-b_{x+r-1} \\ =(c_{x+r-1}-b_{x-1}-b_{x+r-1})+(b_{y-1}-c_{y-1}+b_{y+r-1}) \\ =f(x)+h(y) \]

    我们枚举 \(y\) 查询一下,\([y-r+1,y-1]\) 中满足 \(h(y)+f(x)\le mid\) 的 \(x\) 的个数 , 二维数点问题直接树状数组

tip:

看了巨佬的博客,学了一个新科技,支持前缀和查询 \(0\) 位置的树状数组

代码:

#include<bits/stdc++.h>
#define inl inline 
#define reg register
#define pll pair<long long,long long>
#define mk(x,y) make_pair(x,y)
#define sec second
#define fir first

using namespace std;

namespace zzc
{
    typedef long long ll;
    inl ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }

    const ll maxn = 3e4+5;
    ll n,r,k,sum,ans,lef,rig,mid;
    ll a[maxn],b[maxn],c[maxn];
    pll f[maxn],g[maxn],h[maxn];

    namespace bit
    {
        ll c[maxn];
        inl void clear(){memset(c,0,sizeof(c));}
        inl void add(ll x,ll y){for(reg ll i=x;i<=n;i|=i+1)c[i]+=y;}
        inl ll query(ll x){ll res=0;for(reg ll i=x;i>=0;i&=i+1,--i)res+=c[i];return res;}
    }

    inl ll solve(ll x)
    {
        ll i,j,res=0;
        bit::clear();
        for(j=n-r,i=0;j>=0;res+=bit::query(g[j].sec-r),j--)
            for(;i<=n-r&&g[i].fir+g[j].fir<=x;i++) bit::add(g[i].sec,1);
        if(r==1) return res;
        bit::clear();
        for(j=n-r,i=0;j>=0;res+=bit::query(h[j].sec-1)-bit::query(h[j].sec-r),j--)
            for(;i<=n-r&&f[i].fir+h[j].fir<=x;i++) bit::add(f[i].sec,1);
        return res;
    }

    void work()
    {
        n=read();r=read();k=read();
        for(reg ll i=1;i<=n;i++) a[i]=read(),sum+=a[i];
        for(reg ll i=1;i<=n;i++) b[i]=b[i-1]+read()-a[i];
        for(reg ll i=1;i<=n;i++) c[i]=c[i-1]+read()-a[i];
        for(reg ll i=0;i<n-r+1;i++) g[i]=mk(b[i+r]-b[i],i),f[i]=mk(c[i+r]-b[i]-b[i+r],i),h[i]=mk(b[i+r]+b[i]-c[i],i);
        sort(g,g+n-r+1);sort(f,f+n-r+1);sort(h,h+n-r+1);
        lef=0;rig=c[n];
        while(lef<=rig)
        {
            mid=(lef+rig)>>1;
            if(solve(mid)<k) lef=mid+1;
            else ans=mid,rig=mid-1;
        }
        printf("%lld\n",sum+ans);
    }

}

int main()
{
    zzc::work();
    return 0;
}
上一篇:Basic Wall Maze POJ - 2935简单bfs


下一篇:使用Numpy+OpenCV来增强灰度图像