CodeForces 631E Product Sum

Description

给一个长度为 \(n\) 的序列,任意移动一个数,使得 \(\sum a[i]\times i\) 最大。

\(2\le n\le 2\times 10^5,\left|a[i]\right|\le 10^6\)

Solution

考虑不移动时答案为 \(ans\) ,进行一次移动后答案为 \(ans'\)

考虑固定 \(x\) ,枚举从 \(x\) 移动向 \(y(y\ge x)\)\(y<x\) 时同理):

\[ans' = ans + a[x] \times y - a[x] \times x - (sum[y] - sum[x]) \]

整理一下

\[ans'=ans+(sum[x] - a[x] \times x) + (a[x] \times y - sum[y]) \]

把与 \(x\) 相关的看为常数,定义

\[f(y)=a[x]\times y - sum[y] \]

这玩意儿是凸的,所以可以三分最高点了。

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

template <class T> inline void read(T &x) {
	x = 0; bool flag = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == 45) flag = 1;
	for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; if (flag) x = -x;
}

#define N 200010
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define ll long long

int n;
ll a[N], sum[N], tot;

inline ll calc(int x, int y) {
	if (x <= y) return tot + a[x] * (y - x) - (sum[y] - sum[x]);
	return tot + a[x] * (y - x) + (sum[x - 1] - sum[y - 1]);
}

int main() {
	read(n);
	rep(i, 1, n) read(a[i]), sum[i] = sum[i - 1] + a[i], tot += i * a[i];
	ll ans = -(1ll << 62);
	rep(i, 1, n) {
		int l = 1, r = n;
		ll cur = -(1ll << 62);
		while (l <= r) {
			int mid1 = l + (r - l) / 3, mid2 = r - (r - l) / 3;
			ll ans1 = calc(i, mid1), ans2 = calc(i, mid2);
			if (ans1 > ans2) r = mid2 - 1, cur = max(cur, ans1);
			else l = mid1 + 1, cur = max(cur, ans2);
		}
		ans = max(ans, cur);
	}
	cout << ans;
	return 0;
}
posted @ 2018-07-25 16:53  aziint  阅读(200)  评论(0编辑  收藏  举报
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.