4709: [Jsoi2011]柠檬
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 240 Solved: 105
[ 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
Sample Output
21
先贪心一下下
如果你选的贝壳大小为x,那么这一段的最后一个贝壳和第一个贝壳的大小必须都为x,这样才能保证最优
这样有DP方程:
dp[x] = max(dp[y-1]+s[x]*s[x]*x)
其中保证位置x上和位置y上贝壳大小都为x,s[x]为这一段大小为x贝壳的数量
假设y1<y2<=x,选择y1作为决策点比选择y2作为决策点更优,那么因为平方增幅越来越大的原因y2将再也没用了,所以可以对于每一个颜色开一个栈,每次转移检测栈顶两个决策点哪个更优,如果后面那个更优就直接弹掉栈顶
但可能出现栈顶的第一个决策点比第二个优,第二个决策点却没有第三个优,也就是说弹完之后只能保证弹掉的那个再也没用,却不能保证栈顶最优
……
还是假设栈顶的两个决策点y1和y2(y2是栈顶,y1<y2)当前点为i
这样的话每次添加元素之前,还要检测y1和y2什么时候作为决策点会比当前i点作为决策点更优,如果y1作为决策点在位置k1时优于i,y2作为决策点在位置k2时优于i,若是k1<k2,则说明y2这个决策点在超越i之前就会被y1超越,导致上面蓝字情况发生,弹出,这样就保证了栈顶每个元素超过上一个元素的时间也是单调的
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
#define LL long long
vector<LL> st[100005];
LL n, dp[100005], a[100005], sum[100005], c[100005];
LL Calc(LL x, LL y)
{
return dp[x-1]+(c[y]-c[x]+1)*(c[y]-c[x]+1)*a[y];
}
LL Jud(LL x, LL y)
{
LL l, r, m, now;
l = 1, r = n;
now = c[y]-c[x];
while(l<r)
{
m = (l+r)/2;
if(dp[x-1]+(m+now)*(m+now)*a[x]<dp[y-1]+m*m*a[y])
l = m+1;
else
r = m;
}
return r;
}
int main(void)
{
LL i, j;
scanf("%lld", &n);
for(i=1;i<=n;i++)
scanf("%lld", &a[i]);
for(i=1;i<=n;i++)
{
c[i] = ++sum[a[i]];
while(st[a[i]].size()>=2 && Jud(st[a[i]][st[a[i]].size()-2], i)<Jud(st[a[i]][st[a[i]].size()-1], i))
st[a[i]].pop_back();
st[a[i]].push_back(i);
while(st[a[i]].size()>=2 && Calc(st[a[i]][st[a[i]].size()-2], i)>Calc(st[a[i]][st[a[i]].size()-1], i))
st[a[i]].pop_back();
dp[i] = Calc(st[a[i]][st[a[i]].size()-1], i);
for(j=0;j<st[a[i]].size();j++)
dp[i] = max(dp[i], Calc(st[a[i]][j], i));
}
printf("%lld\n", dp[n]);
return 0;
}
/*
5
2 2 5 2 3
6
1 4 4 4 4 1
*/