题意:
分析:
首先由于 (k) 很大,所以我们没有办法直接求出第 (k) 个值,所以我们考虑二分答案,检验它是不是第 (k) 个
那么我们考虑如何 (check) ,首先方案选择分为两种情况,为了方便起见,我们令 (c_i=c_i-a_i,b_i=b_i-a_i) ,这样 (a) 相当于是必选的,然后我们维护三个序列的前缀和
-
两个区间不相交
[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) 个数,二维数点问题直接树状数组
-
两个区间相交
[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
",sum+ans);
}
}
int main()
{
zzc::work();
return 0;
}