【貪心】【P5078】Tweetuzki 愛軍訓
Description
Tweetuzki 所在的班級有 \(n\) 名學生,座號從 \(1\) 到 \(n\)。有一次,教官命令班上的 \(n\) 名學生按照座號順序從左到右排成一排站好軍姿,其中 \(1\) 號學生在最左邊,\(n\) 號學生在最右邊。
由於同學們站了很久,怨聲載道,仁慈的教官又不希望大家一起解散導致混亂的局面,於是想了一個辦法:教官從最左邊——也就是 \(1\) 號學生身旁出發,走到 \(n\) 號學生右邊後,再折返回到 \(1\) 號同學旁邊。在教官在從 \(1\) 號同學走到 \(n\) 號同學這段路上,當走到某位同學身邊時,他可以選擇讓這位同學出列,也可以等到折返的時候再使這名同學出列。
但是有一些同學在軍訓過程中表現極壞,因此教官希望他們晚一些出列休息。對於 \(i\) 號同學,定義他的“壞值”為 \(w_i\)。教官希望在一次往返過程中,使得所有學生出列,且最大化 \(\sum_{i=1}^{n}~r_i~\times~w_i\) 的值,其中 \(r_i\) 表示 \(i\) 號同學是第 \(r_i\) 位出列的學生。機智的教官一下子就想出了這個方案,Tweetuzki 大為驚訝,於是他去請教教官如何做到。可是他的膽子很小而且“壞值”很大,教官可能不會告訴他,所以他就找到了你。
Input
第一行一個整數 \(n\) 代表序列長度
第二行是 \(n\) 個整數代表這個序列
Output
第一行一個整數,代表最大壞值
下面一行是 \(n\) 個數,按照出列選手字典序最小輸出壞值
Hint
\(0~\leq~n,w_i~\leq~10^6\)
Solution
考慮答案的出列編號序列一定是單峰的,即如果把序列下標作為 \(x\) 座標, 出列選手的序號作為 \(y\) 座標,則函式影象一定如下
並且 \(n\) 一定是峰。於是考慮倒著往前決定出隊的順序,考慮已經決定了 \(i+1~\sim~n\)的出隊順序,那麼 \(i\) 只可能放在這條函式圖線的最左側或者最右側,我們比較他們的貢獻。
考慮 \(i\) 放在最左側的情況,這相當於他後面出隊所有人的 \(r\)
同理,考慮放在右側的貢獻,即為他前面已經放的人的個數,即 \(s_r~=~(n-i)~\times~w_i~+~w_i\)
比較 \(sl\) 和 \(s_r\) 的大小即可。由於序號字典序儘可能小,當兩者相等時優先放在左側即可。
Code
#include <cstdio>
#include <vector>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define putchar(o)\
puts("I am a cheater!")
#define freopen(a, b, c)
#endif
#define rg register
#define ci const int
#define cl const long long
typedef long long int ll;
namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
}
template <typename T>
inline void qr(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
}
template <typename T>
inline void ReadDb(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
if (ch == '.') {
ch = IPT::GetChar();
double base = 1;
while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
}
if (lst == '-') x = -x;
}
namespace OPT {
char buf[120];
}
template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
rg int top=0;
do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
}
const int maxn = 1000010;
int n;
ll ans, sum;
int MU[maxn], temp[maxn];
std::vector<int>pre,pos;
int main() {
freopen("1.in", "r", stdin);
qr(n);
for (rg int i = 1; i <= n; ++i) qr(MU[i]);
for (rg int i = n; i; --i) {
ll sl = sum + MU[i], sr = 1ll * MU[i] * (n - i) + MU[i];
if (sl >= sr) {pre.push_back(i); ans += sl;}
else {pos.push_back(i); ans += sr;}
sum += MU[i];
}
qw(ans, '\n', true);
int sz = pre.size();
for (rg int i = sz - 1; ~i; --i) qw(MU[pre[i]], ' ', true);
sz = pos.size();
for (rg int i = 0; i < sz; ++i) qw(MU[pos[i]], ' ', true);
putchar('\n');
}