题目链接:

小A与最大子段和

 

题意:

给定一个序列a[i],找一个a[i]的连续子序列b[i],使得满足在所有的情况中 小A与最大子段和(斜率dp + 二分) 最大。(m为b的长度)

 

思路:

设 dp[i] 表示以第 i 位为结束位置的最优解。

设 f[i] = a[1]*1+a[2]*2+...+a[n]*n 。

设 sum[i] = a[1]+a[2]+...+a[n] 。

设 j 为b序列的起始位置的前一位(即起始位置是 j+1),因此 0<=j<i 。

动态转移方程:dp[i] = max( f[i] - f[j] - j*(sum[i]-sum[j]) )    (0<=j<i)

此时复杂度为O(n^2),进行斜率优化:

设 j 点优于 k 点,且 j > k ,则: 

小A与最大子段和(斜率dp + 二分)

小A与最大子段和(斜率dp + 二分)

左边式子表示以 i 为x,以 i*sum[i]-f[i] 为y的直线的斜率,由于是>sum[i],所以要维护上凸性质

小A与最大子段和(斜率dp + 二分)

可知:当小A与最大子段和(斜率dp + 二分)时,

j点优于 k 点及之前的所有点 且 优于 i 点及之后的所有点,即 j 点为最优点。因此找第一个斜率小于sum[i]的即为最优点。

由于a[i]中存在负数,所以sum[i]不单调,不能有单调队列找最优点,所以二分查找最优点即可。最后维护一个上凸的性质。

 

Code:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MAX = 2e5 + 100;
const ll MOD = 1e9 + 7;

int n;
int a[MAX];
ll f[MAX], sum[MAX];
ll dp[MAX]; // dp[i]=max(f[i]-f[j]-j*(sum[i]-sum[j]))  0<=j<i
ll q[MAX];

ll up(int j, int k) {
	return (j * sum[j] - f[j]) - (k * sum[k] - f[k]);
}

ll down(int j, int k) {
	return j - k;
}

int bin_search(int l, int r, ll val)
{
	int ans = l;
	while (l < r) {
		int mid = (l + r) >> 1;
		if (mid<r&&up(q[mid + 1], q[mid]) > val * down(q[mid + 1], q[mid])) {
			ans = mid + 1;
			l = mid + 1;
		}
		else {
			r = mid;
		}
	}
	return ans;
}

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	for (int i = 1; i <= n; i++) {
		f[i] = f[i - 1] + a[i] * i;
		sum[i] = sum[i - 1] + a[i];
	}
	dp[0] = 0;
	int left = 1, right = 1;
	q[1] = 0;
	ll ans = -(1e9 + 7);
	for (int i = 1; i <= n; i++) {
		int x = bin_search(left, right, sum[i]);
		int front = q[x];
		dp[i] = f[i] - f[front] - front * (sum[i] - sum[front]);
		while (left < right&&up(q[right], q[right - 1])*down(i, q[right]) <= down(q[right], q[right - 1])*up(i, q[right]))
			right--;
		q[++right] = i;
		ans = max(ans, dp[i]);
	}
	printf("%lld\n", ans);
	return 0;
}

 

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-05-17
  • 2021-06-27
  • 2022-02-22
  • 2021-12-21
  • 2022-12-23
  • 2021-05-23
猜你喜欢
  • 2022-02-25
  • 2022-01-03
  • 2021-10-29
  • 2021-06-07
  • 2022-12-23
  • 2021-07-21
  • 2021-12-09
相关资源
相似解决方案