当前位置: 首页 > 工具软件 > Frets On Fire > 使用案例 >

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

穆英飙
2023-12-01

题目链接: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

 类似资料: