Problem
给定(n)个数(a_1,cdots,a_n),定义(d(i,j) = a_i + a_j + dist(i,j)),其中(dist(i,j) = min(|i - j|,n - |i - j|))。
求一组点对((i_0,j_0)),使得(d(i_0,j_0))最大。
(n le 1 imes 10^6,a_i le 1 imes 10^7)。
Solution
Thinking 1
枚举(i,j),(mathcal{O}(n^2))。
Thinking 2
发现这个(dist(i,j))其实就是(i)和(j)在环上的距离。那么破换成链,可以将(dist)变简洁。
Thinking 3
倍长(a),那么问题变成:在新序列中找一组点对((i_0,j_0)),使得(d(i_0,j_0) = a_{i_0} + a_{j_0} + i_0 - j_0(i_0 > j_0,i_0 - j_0 < n / 2))最大。
考虑对于每一个位置(i),找到最大的(j),发现(a_{i_0} + i_0)是固定的,所以题目变成:枚举(i),找到(a_i + i + left(max_{\j < i,i - j < n / 2}{a_j - j}
ight))
然后这玩意显然可以单调队列啊,(mathcal{O}(n))。
# include <bits/stdc++.h>
using namespace std;
# define int long long
const int N = 2e6 + 5;
int n;
int a[N];
int q[N];
int ans = 0;
int head = 1,tail = 0;
signed main(void)
{
scanf("%lld",&n);
for(int i = 1; i <= n; i++) {scanf("%lld",&a[i]); a[i + n] = a[i];}
n <<= 1;
int len = n / 4;
q[++tail] = 1;
for(int i = 2; i <= n + len; i++)
{
while(head <= tail && i - q[head] > len) ++head;
ans = max(ans,a[i] + i + a[q[head]] - q[head]);
while(head <= tail && a[q[tail]] - q[tail] < a[i] - i) --tail;
q[++tail] = i;
}
printf("%lld
",ans);
return 0;
}