Codeforces 1107G Vasya and Maximum Profit

Codeforces 1107G Vasya and Maximum Profit

题目链接

http://codeforces.com/contest/1107/problem/G

题目大意

有 $n$ 个题,每选择一道题你会获得 $a$ 的收益,同时需要花费 $c_i$ 才能获得第 $i$ 道题。每道题的难度为 $d_i$ ,令 $gap(l, r) = \max\limits_{l \le i < r} (d_{i + 1} – d_i)^2$ 。你需要选择一段连续的题目,使得这些题目的净收益减去 $gap(l, r)$ 最大。

题目分析

由于是连续的一段题目,所以可以考虑使用分治的思想,考虑一个区间分成两个子区间,则答案可能出现在两个子区间中,也可能横跨两个区间。在两个子区间的很好解决,递归求解即可,如果长度为 $1$ 的话就直接返回 $a – c_l$ 即可。

那么考虑横跨两个区间的情况,显然可知,起点一样的 $gap$ 在长度增长的同时一定也是递增的,因此可以分成两种情况讨论,左区间的 $gap$ 大于或者小于右区间的 $gap$,简单合并即可。

官方题解还给出了线段树的做法,将所有相邻点的 $gap$ 从小到大排序,依次将它们添加至线段树中,维护最大连续子序列即可,想法也十分的巧妙。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

const int maxn = 3e5 + 5;

long long n, m;

long long c[maxn];
long long d[maxn];

long long ans = 0;

int read(){
	int x;
	scanf("%d", &x);
	return x;
}

long long sqr(long long x){
	return x * x;
}

int dfs(int l, int r){
	int mid = (l + r) / 2;
	int i, j;
	
	if(l == r){
		ans = max(ans, m - c[l]);
	}else{
		dfs(l, mid);
		dfs(mid + 1, r);
		vector <long long> a[2];
		vector <long long> b[2];
		
		a[0].resize(mid - l + 1);
		a[1].resize(mid - l + 1);
		b[0].resize(r - mid);
		b[1].resize(r - mid);
		
		a[0][0] = m - c[mid];
		a[1][0] = d[mid + 1] - d[mid];
		for(i=1;i<mid-l+1;i++){
			a[0][i] = a[0][i - 1] + m - c[mid - i];
			a[1][i] = max(a[1][i - 1], d[mid - i + 1] - d[mid - i]);
		}
		b[0][0] = m - c[mid + 1];
		b[1][0] = d[mid + 1] - d[mid];
		for(i=1;i<r-mid;i++){
			b[0][i] = b[0][i - 1] + m - c[mid + i + 1];
			b[1][i] = max(b[1][i - 1], d[mid + i + 1] - d[mid + i]);
		}
		
		i = 0, j = 0;
		long long maxa = a[0][0], maxb = b[0][0];
		
		while(i < mid - l + 1){
			 maxa = max(maxa, a[0][i]);
			 
			 while(j + 1 < r - mid and b[1][j + 1] <= a[1][i]){
			 	j++;
			 	maxb = max(maxb, b[0][j]);
			 }
			 
			 ans = max(ans, maxa + maxb - sqr(a[1][i]));
			 i++;
		}
		
		i = 0, j = 0;
		maxa = a[0][0], maxb = b[0][0];
		
		while(j < r - mid){
			 maxb = max(maxb, b[0][j]);
			 
			 while(i + 1 < mid - l + 1 and a[1][i + 1] <= b[1][j]){
			 	i++;
			 	maxa = max(maxa, a[0][i]);
			 }
			 
			 ans = max(ans, maxa + maxb - sqr(b[1][j]));
			 j++;
		}
	}
	
	
	return 0;
}

int main(){
	int i, j;
	
	n = read();
	m = read();
	
	for(i=1;i<=n;i++){
		d[i] = read();
		c[i] = read();
	}
	
	dfs(1, n);
	
	printf("%lld\n", ans);
	
	return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据