大水题。
首先,若区间内只有一根弦,不会对答案有贡献。
我们思考如何对答案产生贡献。我们知道,对于每一个 \(s_i\),都会产生一段 \(s_i+r-l\) 的连续序列,在对 \(s\) 数组排序后,若每个 \(s_i+r-l \ge s_{i+1}\) 则答案为 \(s_n+r-(s_1+l)+1\)。
若够不到下一位呢?我们在 \(s_n+r-(s_1+l)+1\),上减去够不到的位数即可。
过程的实现:我们先对 \(s\) 数组排序,将 \(s_{i+1}-s_i \ge 2\) 的 \(s_{i+1}-s_i\) 压入 \(c\) 数组中,对 \(c\) 排序,并且求其前缀和数组 \(sum\)。设 \(c\) 数组长度为 \(m\)。
对于询问 \(l,r\),若 \(r-l\) 大于 \(c_m\),二分查找 \(c\) 数组中第一个大于 \(r-l\) 的数,\(c_x\)。够不到的位数即为 sum[m]-sum[x-1]-ch*(m-x+1)
。用 \(s_n+r-(s_1+l)+1\) 减去即可。反之,输出 \(s_n+r-(s_1+l)+1\) 即可。
代码(讲的很详细了不放注释了):
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+7;
int a[N],sum[N],c[N];
int n,m;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n);
for(int i=2;i<=n;i++) {
if(a[i]-a[i-1]>1) c[++m]=a[i]-a[i-1]-1;
}
sort(c+1,c+1+m);
for(int i=1;i<=m;i++) sum[i]=sum[i-1]+c[i];
int qu;
cin>>qu;
while(qu--){
int l,r;
cin>>l>>r;
int ch=r-l,ans=a[n]+r-a[1]-l+1;
if(ch<c[m]) {
int w=upper_bound(c+1,c+1+m,ch)-c;
// cout<<w<<'\n';
int su=sum[m]-sum[w-1]-ch*(m-w+1);
ans-=su;
}
cout<<ans<<' ';
}
return 0;
}
标签:ch,Fire,题解,CF1119D,cin,int,数组,排序,sum
From: https://www.cnblogs.com/shootdown/p/18213488