题解:P6958 [NEERC 2017] The Great Wall
题意已经够简洁了不再赘述。
思路:考虑暴力怎么做,就是枚举两个区间,没被覆盖的点价值为 \(a_i\),只被一个区间覆盖的点价值为 \(b_i\),被两个区间覆盖的点价值为 \(c_i\)。然后每种方案的价值存下来排序求出第 \(k\) 小的。
考虑优化。我们发现直接求出第 \(k\) 小的比较困难,但是求出比某个价值小的方案数量比较容易。考虑二分答案 \(x\)。
可以把方案分成两种:
- 两区间无交;
- 两区间有交。
对于无交的情况,我们枚举第一个区间,从之前遍历过的区间中选出与该区间无交的,便得到了一种方案。我们就是要求选择哪些区间和该区间组合价值小于 \(x\),数据结构维护即可。
对于有交的情况,同样枚举第一个区间,从之前遍历过的区间中选出与该区间有交的,便得到了一种方案。我们还是要求选择哪些区间和该区间组合价值小于 \(x\),双指针和数据结构维护即可。
我们还发现 \(a_i \lt b_i \lt c_i\),那么每个点一定会贡献 \(a_i\) 的价值,被至少一个区间覆盖会贡献 \(b_i-a_i\),被两个区间覆盖会贡献 \(c_i-b_i\)。令 \(c_i\gets c_i-b_i\)。
那么对于无交的情况,答案就是 \(\sum\limits_{i=1}^na_i+\sum\limits_{i=l_1}^{r_1}b_i+\sum\limits_{i=l_2,l_2\gt r_1}^{r_2}b_i\)。
对于有交的情况,答案就是 \(\sum\limits_{i=1}^{n}a_i+\sum\limits_{i=l_1}^{r_2}b_i+\sum\limits_{i=l_2}^{r_1}c_i\)。
二分的时候可以不管 \(\sum\limits_{i=1}^{n}a_i\),在最后把答案加上去就可以了。
感觉思路和代码都不是很困难。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
const int N=30005;
#define ll long long
const ll V=30000000000;
int n,r;ll k;
int a[N],b[N],c[N];
ll sumb[N],sumc[N];
int num[N*36],ls[N*36],rs[N*36];
int rt,cnt;
void update(int &x,ll l,ll r,ll k,int v){
if(!x)x=++cnt,num[x]=ls[x]=rs[x]=0;
num[x]+=v;
if(l==r)return;
ll mid=l+r>>1;
k<=mid?update(ls[x],l,mid,k,v):update(rs[x],mid+1,r,k,v);
return;
}
int query(int x,ll l,ll r,ll k){
if(!x)return 0;
if(r<=k)return num[x];
ll mid=l+r>>1;
return k<=mid?query(ls[x],l,mid,k):num[ls[x]]+query(rs[x],mid+1,r,k);
}
inline bool check(ll x){
ll res=0;rt=cnt=0;
for(int i=n-r*2+1;i>=1;--i){
update(rt,-V,V,sumb[i+r*2-1]-sumb[i+r-1],1);
res+=query(rt,-V,V,x-(sumb[i+r-1]-sumb[i-1]));
}
rt=cnt=0;
for(int i=n-r,L=n-r+2,R=n-r+1;i>=1;--i){
while(L>i+1)
--L,update(rt,-V,V,sumb[L+r-1]-sumc[L-1],1);
while(R>i+r-1)
update(rt,-V,V,sumb[R+r-1]-sumc[R-1],-1),--R;
res+=query(rt,-V,V,x+sumb[i-1]-sumc[i+r-1]);
}
return res>=k;
}
inline void solve(){
cin>>n>>r>>k;
ll L=0,R=0,mid,sum=0;
for(int i=1;i<=n;++i)cin>>a[i],sum+=a[i];
for(int i=1;i<=n;++i)cin>>b[i];
for(int i=1;i<=n;++i)cin>>c[i],R+=c[i];
for(int i=1;i<=n;++i){
c[i]-=b[i];b[i]-=a[i];
sumc[i]=sumc[i-1]+c[i];
sumb[i]=sumb[i-1]+b[i];
}
while(L<R){
mid=L+R>>1;
check(mid)?R=mid:L=mid+1;
}
cout<<sum+R<<endl;
return;
}
int main(){
IOS;
int _=1;
while(_--)solve();
return 0;
}
/*
华风夏韵,洛水天依!
*/
记录。

浙公网安备 33010602011771号