题意:n = 20w的数列, 价值val = sigma(i * Ai), 可以把任意一个数移到任意位置, 求价值最大值
思路:对每个数,分别左右移动, 三分求得移动的最佳位置
三分:
注意把要三分的区间向左向右各扩大一格,这样就不会使mid == midd出现了,避免了出错。
最后定出lb和ub的时候,要判断是否在合法区间外
代码:
import java.util.*;
import java.math.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
InputStream inputStream = System.in;
OutputStream outputStream = System.out;
Scanner in = new Scanner(inputStream);
PrintWriter out = new PrintWriter(outputStream);
solve(in, out);
out.close();
}
static long []a;
static long []val, f, b;
static void solve(Scanner in, PrintWriter out) {
int n = in.nextInt();
a = new long [n + 1];
val = new long [n + 1];
f = new long [n + 1];
b = new long [n + 1];
for(int i = 1; i <= n; i ++) a[i] = in.nextInt();
for(int i = 1; i <= n; i ++) val[i] = val[i - 1] + i * a[i];
for(int i = 1; i <= n; i ++) f[i] = f[i - 1] + (i - 1) * a[i];
for(int i = 1; i <= n; i ++) b[i] = b[i - 1] + (i + 1) * a[i];
long ans = val[n];
for(int i = 1; i <= n; i ++) {
int lb = Math.min(n, i + 1) - 1, ub = n + 1;
while(ub - lb > 1) {
int mid = (lb + ub) >> 1;
int midd = (mid + ub) >> 1;
long x = val[n] - val[mid] + val[i - 1] + mid * a[i] + (f[mid] - f[i]);
long y = val[n] - val[midd] + val[i - 1] + midd * a[i] + (f[midd] - f[i]);
if(x > y) ub = midd;
else lb = mid;
}
if(lb != Math.min(n, i + 1) - 1)
ans = Math.max(ans, val[n] - val[lb] + val[i - 1] + lb * a[i] + f[lb] - f[i]);
if(ub != n + 1)
ans = Math.max(ans, val[n] - val[ub] + val[i - 1] + ub * a[i] + f[ub] - f[i]);
lb = 0;
ub = Math.max(1, i - 1) + 1;
while(ub - lb > 1) {
int mid = (lb + ub) >> 1;
int midd = (mid + ub) >> 1;
long x = val[n] - val[i] + val[mid - 1] + mid * a[i] + b[i - 1] - b[mid - 1];
long y = val[n] - val[i] + val[midd - 1] + midd * a[i] + b[i - 1] - b[midd - 1];
if(x > y) ub = midd;
else lb = mid;
}
if(lb != 0)
ans = Math.max(ans, val[n] - val[i] + val[lb - 1] + lb * a[i] + b[i - 1] - b[lb - 1]);
if(ub != Math.max(1, i - 1) + 1)
ans = Math.max(ans, val[n] - val[i] + val[ub - 1] + ub * a[i] + b[i - 1] - b[ub - 1]);
}
out.println(ans);
out.flush();
}
static class Scanner {
BufferedReader br;
StringTokenizer st;
public Scanner(InputStream in) {
br = new BufferedReader(new InputStreamReader(in));
eat("");
}
private void eat(String s) {
st = new StringTokenizer(s);
}
public String nextLine() {
try {
return br.readLine();
} catch (IOException e) {
return null;
}
}
public boolean hasNext() {
while (!st.hasMoreTokens()) {
String s = nextLine();
if (s == null)
return false;
eat(s);
}
return true;
}
public String next() {
hasNext();
return st.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
public BigInteger nextBigInteger() {
return new BigInteger(next());
}
}
}