T701316 重排 (rearrange) 赛后题解
题目传送门 + 原题传送门
思路
静态原问题
给定长度为 \(n\) 的正整数序列 \(a\),你可以任意排列序列 \(a\),使得以下式子的值最大:
\[f(a)=\sum_{i=2}^{n} |a_{i}-a_{i-1}| \]
发现有绝对值求最大值,考虑将数分为大、小两部分,交错放置。
将大的中最小的、小的中最大的放两边更优。
令大的和为 sum2,小的和为 sum1,大的中最小值为 bmin,小的中最大值为 smax,若 n 为奇数令中位数为 mid。
则 \(\begin{align*}\begin{split}ans= \left \{\begin{array}{ll} 2(sum2-sum1)-(bmin-smax), & n \equiv 0\pmod 2\\ 2(sum2-sum1)-\min(bmin-mid,mid-smax), &n \equiv 1\pmod 2\end{array}\right.\end{split}\end{align*}\)
动态问题
需要动态维护以上 4 或 5 个量,求出答案即可。
做法
对顶堆维护,参考 P1168 中位数
时间复杂度:\(O(m\log_2m)\),可以通过 \(m\le 3\times 10^6\)。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[3000005];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
freopen("rearrange.in", "r", stdin);
freopen("rearrange.out", "w", stdout);
int n, T;
cin >> n >> T;
for(int i = 1; i <= n; i ++)
{
cin >> a[i];
}
priority_queue<int> pq1; //小的部分,大根堆,top 为 smax
priority_queue<int, vector<int>, greater<int> > pq2; //大的部分,小根堆,top 为 bmin
int ans = 0, las = 0, sum1 = 0, sum2 = 0; //las 为上一轮答案(此题强制在线)
if(n == 1) //特判 n=1,因为对顶堆中至少得有 2 个元素
{
cout << 0;
return 0;
}
pq1.push(min(a[1], a[2])), pq2.push(max(a[1], a[2]));
sum1 = min(a[1], a[2]), sum2 = max(a[1], a[2]);
las = max(a[1], a[2]) - min(a[1], a[2]);
ans ^= las;
int mid;
for(int i = 3; i <= n; i ++)
{
a[i] ^= las * T;
if(i & 1)
{
if(a[i] < pq1.top()) //属于小的一半
{
mid = pq1.top();
sum1 -= pq1.top() - a[i];
pq1.pop();
pq1.push(a[i]);
}
else if(a[i] > pq2.top()) //属于大的一半
{
mid = pq2.top();
sum2 -= pq2.top() - a[i];
pq2.pop();
pq2.push(a[i]);
}
else //为中位数
{
mid = a[i];
}
las = 2 * (sum2 - sum1) - min(pq2.top() - mid, mid - pq1.top());
ans ^= las;
}
else
{
if(mid <= a[i]) //把中位数放回去
{
sum1 += mid;
pq1.push(mid);
}
else
{
sum2 += mid;
pq2.push(mid);
}
if(a[i] < pq1.top()) //属于小的一半
{
if(pq1.size() == (i >> 1)) //堆满了
{
pq2.push(pq1.top());
sum2 += pq1.top();
sum1 -= pq1.top() - a[i];
pq1.pop();
pq1.push(a[i]);
}
else
{
sum1 += a[i];
pq1.push(a[i]);
}
}
else if(a[i] > pq2.top()) //属于大的一半
{
if(pq2.size() == (i >> 1)) //堆满了
{
pq1.push(pq2.top());
sum1 += pq2.top();
sum2 -= pq2.top() - a[i];
pq2.pop();
pq2.push(a[i]);
}
else
{
sum2 += a[i];
pq2.push(a[i]);
}
}
else
{
if(pq1.size() == (i >> 1)) //哪个没满放哪个
{
sum2 += a[i];
pq2.push(a[i]);
}
else
{
sum1 += a[i];
pq1.push(a[i]);
}
}
las = 2 * (sum2 - sum1) - (pq2.top() - pq1.top());
ans ^= las;
}
}
cout << ans;
return 0;
}
hello, I'm yuzihang, if you need to copy this, please quote this url: https://www.cnblogs.com/yuzihang/p/19268969

浙公网安备 33010602011771号