[BZOJ4709]柠檬

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
//Flute 先从左端取下 4 只贝壳,它们的大小为 2, 2, 5, 2。选择 s0 = 2,那么这一段
里有 3 只大小为 s0 的贝壳,通过魔法可以得到 2×3^2 = 18 只柠檬。再从右端取下最后一
只贝壳,通过魔法可以得到 1×3^1 = 3 只柠檬。总共可以得到 18 + 3 = 21 只柠檬。没有
比这更优的方案了。
 
第一次推决策单调性的dp
代码:
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<vector>
 6 #define M 100010
 7 #define ll long long
 8 #define a1 st[x][st[x].size()-2]
 9 #define a2 st[x][st[x].size()-1]
10 using namespace std;
11 
12 int n,a[M],cnt[M],s[M];
13 ll f[M];
14 vector<int>st[M];
15 
16 ll cal(int x,int y) {return f[x-1]+(ll)a[x]*y*y;}
17 
18 int get(int x,int y)
19 {
20     int l=1,r=n,ans=n+1;
21     while(l<=r)
22     {
23         int mid=(l+r)/2;
24         if(cal(x,mid-s[x]+1)>=cal(y,mid-s[y]+1)) ans=mid,r=mid-1;
25         else l=mid+1;
26     }
27     return ans;
28 }
29 
30 int main()
31 {
32     scanf("%d",&n);
33     for(int i=1;i<=n;i++)
34     {
35         int x;scanf("%d",&x);
36         a[i]=x; s[i]=++cnt[x];
37         while(st[x].size()>=2&&get(a1,a2)<=get(a2,i)) st[x].pop_back();
38         st[x].push_back(i);
39         while(st[x].size()>=2&&get(a1,a2)<=s[i]) st[x].pop_back();
40         f[i]=cal(a2,s[i]-s[a2]+1);
41     }
42     printf("%lld",f[n]);
43     return 0;
44 }

猜你喜欢

转载自www.cnblogs.com/Slrslr/p/9754455.html