Codeforces Global Round 2 D 差分 + 前缀和 + 二分

https://codeforces.com/contest/1119/problem/D

题意

有n个数组,每个数组大小为\(10^{18}+1\)且为等差数列,给出n个数组的\(s[i]\),q次询问,每次询问一个区间[l,r],问所有数组的[l,r]区间一共有多少不同的数

题解

  • 结果只与选择的区间长度len有关,还有和两个数组s[i]的差cha有关
    • 若len<=cha,则没有重复,即\(2*len\)
    • 若len>cha,则前面一个数组可以取满len个,后面的数组只能cha个,即\(cha+len\)
  • 根据以上规律,将a数组进行排序后差分,对差分进行排序,然后做前缀和,每次二分查找出最大的p满足b[p]<=x
  • 这里二分查找需要特判l>r的情况

代码

#include<bits/stdc++.h>
#define ll long long 
#define MAXN 100005
using namespace std;
ll a[MAXN],b[MAXN],s[MAXN],q,n,x,p,ans,l,r,sz;

int fd(ll x){
    int l=1,r=sz-1,res=0;
    while(l<r){
        int mid=(l+r)/2;
        if(b[mid]<=x)l=mid+1;
        else r=mid;
    }
    if(l>r||b[l]>x)l--;                         //特判
    return l;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    sort(a+1,a+n+1);
    sz=unique(a+1,a+n+1)-(a+1);
    for(int i=2;i<=sz;i++)b[i-1]=a[i]-a[i-1];
    sort(b+1,b+sz);
    for(int i=1;i<sz;i++)s[i]=s[i-1]+b[i];
    cin>>q;
    while(q--){
        scanf("%lld%lld",&l,&r);
        x=r-l+1;
        p=fd(x);
        ans=s[p]+(sz-p)*x;
        printf("%lld ",ans);
    }
}

猜你喜欢

转载自www.cnblogs.com/VIrtu0s0/p/10808913.html
今日推荐