D. Frets On Fire(二分 + 前缀和)

Problem - D - Codeforces

Miyako带着一个乌克丽丽来到跳蚤王国。她与当地的跳蚤居民成为好朋友,并每天为他们演奏美妙的音乐。
作为国报,跳蚤们为她制作了一个更大的乌克丽E:它有n根这,每核这上都有(1018+1)个品位(ires),从0到10106编号。跳蚤们使用数组s1、s1..、sn来描述乌克丽丽的调音,即第根弦上第j个品位的音高是整数si+j。
Miyako即将离开王国,但跳蚤们希望Miyako能回答一些最后的问题。
每个问题的形式为:“如果我们考虑所有弦上[l,r](包括端点)之间的品位,则有多少不同的音高?”
Miyako即将访问蟋螭王国,没有时间回答所有的问题。请帮助她完成这个任务!
具体而言,给定一个具有n行和(1018+1)列的矩阵,其中第i行和第j列(O<j≤1018)的单元格包含整数si+j。
您需要回答q个查询,在第k个查询中,您必须回答从第Ik列到第rk列(包括)的矩
阵中不同整数的数量。
输入:
第一行包含一个整数n (1<n<100000)-弦的数量。
第二行包含n个整数s1、s2、....、sn (0<si≤1018)-乌克丽丽的调音。第三行包含一个整数q (1≤q≤100000)-问题的数量。
接下来的q行中的第k行包含两个整数lk、rk (O≤lk≤rk≤1018)–来自跳蚤们的一个问题。
输出:
为每个问题输出—个数字,用空格分隔-不同音高的数量。

Examples

input

Copy

6
3 1 4 1 5 9
3
7 7
0 2
8 17

output

Copy

5 10 18

input

Copy

2
1 500000000000000000
2
1000000000000000000 1000000000000000000
0 1000000000000000000

output

Copy

2 1500000000000000000

题解:

1 2 3 4    5  6  7 

2 3 4 5    6  7  8

4 5 6 7    8  9  10

7 8 9 10 11 12 13

先对数组进行排序,假如先取一列,发现各个区间无交集,贡献是4

如果取两列,对于前两行,贡献多了1,后两个贡献正常加2(两行嘛)

如果取三列,对于前三行,贡献多了2,最后一行正常加1

如果取四列,对于前4行,贡献多了3,

我么可以发现一个规律,如果我么在得到,数组a的,相邻差,然后排序,

得到差的前缀和,如果对根据所求区间的大小,对差进行二分,得到下标

那么此时下标的前缀和就是贡献多的数,后面(n - p)就是后几行的正常贡献(因为区间的长度无法影响到后面几行,是他们相交)
 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
 #define int long long
 typedef pair<int,int> PII;
 int mod = 1e9 + 7;
int a[100050];
struct node
{
	int x;
	int sum;
}b[100050];
bool cmp(node a,node b)
{
	return a.x < b.x;
}
void solve()
{
	int n;
	cin >> n;
	for(int i = 1;i <= n;i++)
	{
		cin >> a[i];
	}
	sort(a + 1,a + 1 + n);
	int cnt = 0;
//	for(int i = 1;i <= k;i++)
//	cout << a[i] <<" ";

	for(int i = 2;i <= n;i++)
	{
		b[++cnt].x = a[i] - a[i - 1];
	}
	sort(b + 1,b + 1 + cnt,cmp);
	for(int i = 1;i <= cnt;i++)
	{
		b[i].sum = b[i - 1].sum + b[i].x;
	}
	int q;
	cin >> q;
	while(q --)
	{
		int x,y;
		cin >> x >> y;
		int w = y - x + 1;
		int l = 0,r = cnt;
		while(l <= r)
		{
			int mid = (l + r)/2;
			if(b[mid].x > w)
			{
				r = mid - 1;
			}
			else
			{
				l = mid + 1;
			}
		}
		cout << (n - l + 1)*w + b[l - 1].sum <<" ";
	}
	
}
//5 7 8 9 10

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int t = 1;
//	cin >> t;
	while(t--)
	{
		solve(); 
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值