zoukankan      html  css  js  c++  java
  • 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("
    ");
        return 0;
    }
  • 相关阅读:
    【0003】与随机数有关的一些问题
    【0001】排序法与查找方式
    【0002】斐波那契数列,迷宫,汉诺塔
    【0001】C程序的编译过程
    django学习——request.POST.get(‘key’) 、 request.GET.get('key', '')
    django 删除数据库表后重新同步的方法
    Django链接mysql数据库报错1064
    sql练习题
    jmeter连接数据库
    购物车程序练习
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/10673895.html
Copyright © 2011-2022 走看看