4709: [Jsoi2011]柠檬
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 185 Solved: 75
[ Submit][ Status][ Discuss]
Description
Flute 很喜欢柠檬。它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬。贝壳一共有 N (1 ≤ N
≤ 100,000) 只,按顺序串在树枝上。为了方便,我们从左到右给贝壳编号 1..N。每只贝壳的大小不一定相同,
贝壳 i 的大小为 si(1 ≤ si ≤10,000)。变柠檬的魔法要求,Flute 每次从树枝一端取下一小段连续的贝壳,并
选择一种贝壳的大小 s0。如果 这一小段贝壳中 大小为 s0 的贝壳有 t 只,那么魔法可以把这一小段贝壳变成 s
0t^2 只柠檬。Flute 可以取任意多次贝壳,直到树枝上的贝壳被全部取完。各个小段中,Flute 选择的贝壳大小 s
0 可以不同。而最终 Flute 得到的柠檬数,就是所有小段柠檬数的总和。Flute 想知道,它最多能用这一串贝壳
变出多少柠檬。请你帮忙解决这个问题。
Input
第 1 行:一个整数,表示 N。
第 2 .. N + 1 行:每行一个整数,第 i + 1 行表示 si。
Output
仅一个整数,表示 Flute 最多能得到的柠檬数。
Sample Input
5
2
2
5
2
3
2
2
5
2
3
Sample Output
21
//Flute 先从左端取下 4 只贝壳,它们的大小为 2, 2, 5, 2。选择 s0 = 2,那么这一段
里有 3 只大小为 s0 的贝壳,通过魔法可以得到 2×3^2 = 18 只柠檬。再从右端取下最后一
只贝壳,通过魔法可以得到 1×3^1 = 3 只柠檬。总共可以得到 18 + 3 = 21 只柠檬。没有
比这更优的方案了。
//Flute 先从左端取下 4 只贝壳,它们的大小为 2, 2, 5, 2。选择 s0 = 2,那么这一段
里有 3 只大小为 s0 的贝壳,通过魔法可以得到 2×3^2 = 18 只柠檬。再从右端取下最后一
只贝壳,通过魔法可以得到 1×3^1 = 3 只柠檬。总共可以得到 18 + 3 = 21 只柠檬。没有
比这更优的方案了。
HINT
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int M = 10000 + 5;
const int N = 100000 + 5;
long long f[N];
int s[N],cot[M],a[N],n;
vector<int> st[N];
long long ji( int x, int y ){ return f[x-1] + (long long)a[x] * y * y; }
int fron( int x, int y ){
int l = 1, r = n, pos = r+1;
while( l <= r ){
int mid = ( l + r ) >> 1;
if( ji(x,mid-s[x]+1) >= ji(y,mid-s[y]+1) ){ pos = mid; r = mid-1; } else l = mid+1;
} return pos;
}
int main(){
scanf("%d", &n);
for( int i = 1,x; i <= n; i++ ){
scanf("%d", &x); a[i] = x; s[i] = ++cot[x];
while( st[x].size() >= 2 && fron(st[x][st[x].size()-2],st[x][st[x].size()-1]) <= fron(st[x][st[x].size()-1],i)) st[x].pop_back();
st[x].push_back(i);
while( st[x].size() >= 2 && fron(st[x][st[x].size()-2],st[x][st[x].size()-1]) <= s[i] ) st[x].pop_back();
f[i] = ji( st[x][st[x].size()-1], s[i]-s[st[x][st[x].size()-1]]+1 );
}
printf("%lld",f[n]);
return 0;
}