D - 1D Country(AtCoder Beginner Contest 371)

题目链接:

D - 1D Country (atcoder.jp)

题目描述:

数据范围:

输入输出:

题目分析:

典型的l, r 区间问题,即是前缀和问题,但是注意到数据范围, 数据范围1e-9 到 1e9 数据范围,要是从最小到最大直接for循环去模拟的话,时间复杂度太高了O(2e9),注意到极限总共才2e5个居民,要去想到映射,不在关心他们的位置,而去把下标转换为从1开始的,然后在询问l, r这段区间的时候二分去查到对应的l, r他们映射后的位置,然后用前缀和公式sum[映射后的r] - sum[映射后的l - 1]就是最后的答案,但是我用map去写的时候卡到了最后一个数据,但是用数组就过掉了,why?

最后一个数据没过的代码:

#include<bits/stdc++.h>
#define int long long 

using namespace std;

const int N = 2e5 + 10;

map<int, int>mp, ren, sum;
//map<int, int>ren;
int a[N];

signed main() {
	int n, m;
	cin >> n;

	for(int i = 1; i <= n; i ++ ) {
		cin >> a[i];
	}
	for(int i = 1; i <= n; i ++ ) {
		int x;
		cin >> x;
		mp[a[i]] += x;
	}
//	sort(a + 1, a + n + 1);
	//a[0] = 0;
//	sum[a[1] - 1] = 0;
	sum[a[1]] = mp[a[1]];
	
	for(int i = 2; i <= n; i ++ ) {
		sum[a[i]] = sum[a[i - 1]] + mp[a[i]]; 
	}
//	for(int i = 1; i <= n; i ++ ) {
//		cout << "a[i] = " << a[i] << " sum = " << sum[a[i]] << endl;
//	}
	cin >> m;
	// 二分的是位置 
	while(m -- ) {
		int l, r;
		cin >> l >> r;
		// 二分第一个大于等于l的位置
		int ll = 0, rr = n + 1;
		while(ll + 1 < rr) {
			int mid = ll + rr >> 1;
			if(a[mid] < l) ll = mid;
			else rr = mid;
		}
		int st = ll + 1;
	//	cout << "st = " << st << endl;
		// 二分最后一个小于等于r的位置 
		ll = 0, rr = n + 1;
		while(ll + 1 < rr) {
			int mid = ll + rr >> 1;
			if(a[mid] <= r)ll = mid;
			else rr = mid;
		}
		int en = ll;
		
		if(r > a[n]) {
			en = n;
		}
		if(l < a[1]) {
			st = 1;
		}
//		cout << "st - 1 = " << st - 1 << endl;
//		cout << "a[st - 1] = " << a[st - 1] << endl;
//		cout << "en = " << en << endl;
//		cout << "sumEnd = " << sum[a[en]] << endl;
//		cout << "sumStart = " << sum[a[st - 1]] << endl;
		if(st == 1) {
			cout << sum[a[en]] << endl;
		} else {
			cout << sum[a[en]] - sum[a[st - 1]] << endl;
		}
		
	}
	return 0;
}
/*
7
-10 -5 -3 -1 0 1 4
2 5 6 5 2 1 7
1
-10 -4

*/

运行结果:

 

正确代码:

#include<bits/stdc++.h>
#define int long long 

using namespace std;

const int N = 2e5 + 10;

int a[N], sum[N];

signed main() {
	int n, m;
	cin >> n;

	for(int i = 1; i <= n; i ++ ) {
		cin >> a[i];
	}
	for(int i = 1; i <= n; i ++ ) {
		int x;
		cin >> x;
		sum[i] = sum[i - 1] + x;
	}
	
	cin >> m;
	// 二分的是位置 
	while(m -- ) {
		int l, r;
		cin >> l >> r;
		// 二分第一个大于等于l的位置
		int ll = 0, rr = n + 1;
		while(ll + 1 < rr) {
			int mid = ll + rr >> 1;
			if(a[mid] < l) ll = mid;
			else rr = mid;
		}
		int st = ll + 1;
	//	cout << "st = " << st << endl;
		// 二分最后一个小于等于r的位置 
		ll = 0, rr = n + 1;
		while(ll + 1 < rr) {
			int mid = ll + rr >> 1;
			if(a[mid] <= r)ll = mid;
			else rr = mid;
		}
		int en = ll;
		cout << sum[en] - sum[st - 1] << endl;		
	}
	return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FindYou.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值