cf-Global Round2-D. Frets On Fire(二分)

题目链接:http://codeforces.com/contest/1119/problem/D

题意:给n(<=1e5)个数s[i],i=1..n,(0<=s[i]<=1e18)分别表示每一行的起始值,每个组有1e18+1列,第i行第j(0<=j<=1e18)列的值为s[i]+j,有q组询问(q<=1e5),每组询问给出两个值l,r,问每一行的第 l 列到第 r 列有多少个不同的值。

思路:题意很简单,但看到数据量,q<=1e5,就要想到能不能预处理之类的。显然问题在于每一行可能出现数据交叉的情况,先将s数组按升序排列,每一行最多有w=r-l+1个不同的数,不访从最后一行开始,即第n行有w个不同的数,则第i(1<=i<n)行有min(si+1-si,w)个数(与前面已经出现的数不同),显然这里的si+1-si是可以提前算出来的,那么我们用di=di+1-di,然后将d[i]按升序排序,sum[i]表示前i个d[i]之和。这样在询问的时候输入得到w,然后只需二分查找到第一个di>=w即可。

AC代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
int n,q;
LL s[100005],d[100005],sum[100005];

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        scanf("%lld",&s[i]);
    sort(s+1,s+n+1);
    for(int i=1;i<n;++i)
        d[i]=s[i+1]-s[i];
    sort(d+1,d+n);
    for(int i=1;i<n;++i)
        sum[i]=sum[i-1]+d[i];
    scanf("%d",&q);
    while(q--){
        LL t1,t2,w;
        scanf("%lld%lld",&t1,&t2);
        w=t2-t1+1;
        d[n]=w;
        int l=1,r=n,m;
        while(l<=r){
            m=(l+r)>>1;
            if(d[m]>=w) r=m-1;
            else l=m+1;
        }
        printf("%lld ",sum[l-1]+w*(n-l+1));
    }
    printf("\n");
    return 0;
}

 

转载于:https://www.cnblogs.com/FrankChen831X/p/10673895.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值