题意:
n个数,每个数是一个序列的起点,后面无限个数每个数比前一个大1,形成的这n个序列。t次查询,每次查询所有序列的区间l--r,所有区间的l--r中的数形成一个集合,输出这个集合中一共有多少种数。
思路:
这里数的大小1e18说明这是一道规律题,这里有一个规律,对所有数从大到小排序后,求一个差分数组cf,代表两个数之间的差,如果r-l+1就是查询的区间的长度,那么每个数产生序列对这个答案的贡献度就是min(r-l+1,cf[i] )这个cf[i]即是当前数与上一个数的差分值。值得注意的是,第一个数序列的贡献度一定是(r-l+1)。知道这个规律以后,将差分数组排序后,可知,当查询的(r-l+1)<cf[i]时之后每个序列的贡献度都是(r-l+1),对于这个界限之前的贡献度,可以对差分数组求前缀和O(1)得到,而这个界限可以通过对有序的cf序列二分得到。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[100100],cf[100100],sum[100100];
int main(){
int n;cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n);
n=unique(a,a+n)-a;
for(int i=1;i<n;i++){
cf[i]=a[i]-a[i-1];
}
sort(cf+1,cf+n);
for(int i=1;i<n;i++){
sum[i]=sum[i-1]+cf[i];
}
// for(int i=1;i<n;i++){
// cout<<cf[i]<<endl;
// }
// cout<<endl;
int t;cin>>t;
while(t--){
ll l,r;cin>>l>>r;
ll len=r-l+1;
ll x=upper_bound(cf+1,cf+n,len)-cf;
// cout<<x<<" asd"<<endl;
cout<<len+sum[x-1]+(n-x)*(len)<<endl;
// cout<<a[0]<<" "<<sum[x-1]<<endl;
}
return 0;
}