题目大意
我们定义“排列的价值”为所有区间的最大值之和。一个最好的排列,应当是在所有排列中,价值最高的。
现在有
N
个整数,他们是从
解题思路
考虑一个数对答案的贡献,若这个数所在位置是x,左边比它大的最近的数的位置是
l
,右边比它大的最近的数的位置是
但是
N
有
程序
//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
typedef unsigned long long LL;
const int MAXN = 1e3 + 5;
struct Num {
int P[600];
};
char S[200];
map<LL,int> Map;
Num N, Get[1000], Len[1000], Work, One, Ans;
int Last[MAXN], Next[MAXN * 10], Go[MAXN * 10], tot;
int Cnt, Rd[MAXN], Ord[MAXN];
void Link(int u, int v) {
Next[++ tot] = Last[u], Last[u] = tot, Go[tot] = v;
}
LL GetHash(Num Now) {
LL Ans = 0;
for (int i = Now.P[0]; i; i --)
Ans = Ans * 11 + Now.P[i];
return Ans;
}
Num Dec(Num A) {
A.P[1] --;
int p = 1;
while (A.P[p] < 0) {
A.P[p] += 10;
A.P[p + 1] --;
p ++;
}
while (A.P[A.P[0]] == 0 && A.P[0] > 0) A.P[0] --;
return A;
}
Num Div2(Num A) {
for (int i = A.P[0]; i; i --) {
if (A.P[i] % 2 == 1 && i > 1) A.P[i - 1] += 10;
A.P[i] /= 2;
}
while (A.P[A.P[0]] == 0 && A.P[0] > 0) A.P[0] --;
return A;
}
Num Inc(Num A) {
A.P[1] ++;
int p = 1;
while (A.P[p] > 9) {
A.P[p] -= 10;
A.P[p + 1] ++;
p ++;
}
while (A.P[A.P[0] + 1] > 0) A.P[0] ++;
return A;
}
Num Add(Num A, Num B) {
Num C;
memset(C.P, 0, sizeof C.P);
C.P[0] = max(A.P[0], B.P[0]);
for (int i = 1; i <= C.P[0]; i ++) {
C.P[i] = C.P[i] + A.P[i] + B.P[i];
C.P[i + 1] += C.P[i] / 10;
C.P[i] = C.P[i] % 10;
}
while (C.P[C.P[0] + 1] > 0) C.P[0] ++;
return C;
}
Num Mul(Num A, Num B) {
Num C;
memset(C.P, 0, sizeof C.P);
C.P[0] = A.P[0] + B.P[0] - 1;
for (int i = 1; i <= A.P[0]; i ++)
for (int j = 1; j <= B.P[0]; j ++) {
C.P[i + j - 1] = C.P[i + j - 1] + A.P[i] * B.P[j];
C.P[i + j] = C.P[i + j] + C.P[i + j - 1] / 10;
C.P[i + j - 1] = C.P[i + j - 1] % 10;
}
while (C.P[C.P[0] + 1] > 0) C.P[0] ++;
return C;
}
bool Comp(Num A, Num B) {
if (A.P[0] < B.P[0]) return 1;
if (B.P[0] < A.P[0]) return 0;
for (int i = A.P[0]; i; i --) {
if (A.P[i] < B.P[i]) return 1;
if (B.P[i] < A.P[i]) return 0;
}
return 1;
}
int Div(Num Now) {
if (Now.P[0] == 0) return 0;
LL Hnum = GetHash(Now);
if (Map[Hnum]) return Map[Hnum];
Get[++ Cnt] = Now;
Map[Hnum] = Cnt;
Now = Dec(Now);
Num A = Div2(Now);
Num B;
if (Now.P[1] % 2 == 0) B = A; else
B = Inc(A);
int Ord = Cnt;
int NA = Div(A), NB = Div(B);
if (NA) Link(Ord, NA), Rd[NA] ++;
if (NB) Link(Ord, NB), Rd[NB] ++;
return Ord;
}
void Dfs(int Now) {
static int D[MAXN];
int top = 1;
D[top] = 1;
while (top) {
int Now = D[top --];
for (int p = Last[Now]; p; p = Next[p]) {
int v = Go[p];
Len[v] = Add(Len[v], Len[Now]);
Rd[v] --;
if (!Rd[v]) D[++ top] = v;
}
}
}
bool Cmp(int A, int B) {
return Comp(Get[A], Get[B]);
}
void Calc() {
for (int i = 1; i <= Cnt; i ++) Ord[i] = i;
sort(Ord + 1, Ord + 1 + Cnt, Cmp);
for (int i = 1; i <= Cnt; i ++) {
int Now = Ord[i];
Num Sum = Div2(Mul(Add(Inc(Work), Add(Work, Len[Now])), Len[Now]));
Get[Now] = Inc(Get[Now]);
Num A = Div2(Get[Now]), B;
if (Get[Now].P[1] % 2 == 0) B = A; else
B = Inc(A);
Ans = Add(Ans, Mul(Mul(A, B), Sum));
Work = Add(Work, Len[Now]);
}
for (int i = Ans.P[0]; i; i --)
printf("%d", Ans.P[i]);
}
int main() {
scanf("%s", S + 1);
N.P[0] = strlen(S + 1);
for (int i = N.P[0]; i; i --) N.P[i] = S[N.P[0] - i + 1] - '0';
One.P[0] = One.P[1] = 1;
Len[1] = One;
Div(N);
Dfs(0);
Calc();
}