[JSOI2011]檸檬

推(chao)式子:c++

令$f_i$表示以i結尾時取得的最大值,$c_i$表示$a_i$這個數在第i個位置是第$c_i$次出現,則有:git

$$f_i=f_{j-1}+(c_i-c_j+1)^2*a_i$$spa

不妨設j>k時從j轉移比從i轉移更優code

則有:blog

$$f_{j-1}+(c_i-c_j+1)^2·a_i>f_{k-1}+(c_i-c_k+1)^2·a_i$$get

其中$a_i$是常數,咱們考慮最後再乘回去,因此先無論它it

而後化簡有:io

$$(f_{j-1}+(c_j-1)^2)-(f_{k-1}+(c_k-1)^2)>2c_i(c_j-c_k)$$class

不妨再設$dp_i=f_{i-1}+(c_i-1)^2$top

$$dp_j-dp_k>2c_i(c_j-c_k)$$

$$\frac{dp_j-dp_k}{c_j-c_k}>2c_i$$

好了因而咱們把斜率搞出來了

要求最大值,因此用單調棧維護上凸殼,棧頂元素最優

附上抄來的代碼

 

 1 //張家奇怎麼又AKIOI了呀,怎麼CSP也滿分啊...怎麼清北每天給他打電話啊...怎麼會有這麼強的人啊
 2 #include<bits/stdc++.h>
 3 #define int long long
 4 #define writeln(x)  write(x),puts("")
 5 #define writep(x)   write(x),putchar(' ')
 6 using namespace std;
 7 inline int read(){
 8     int ans=0,f=1;char chr=getchar();
 9     while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();}
10     while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
11     return ans*f;
12 }void write(int x){
13     if(x<0) putchar('-'),x=-x;
14     if(x>9) write(x/10);
15     putchar(x%10+'0');
16 }const int M = 1E5+5;
17 int n,m,a[M];
18 inline int sqr(int x){return x*x;}
19 namespace Solution_1{//n^2logn的暴力轉移 
20     int f[M];vector<int>pos[M];
21     inline int Count(int color,int l,int r){
22         l=lower_bound(pos[color].begin(),pos[color].end(),l)-pos[color].begin();
23         r=upper_bound(pos[color].begin(),pos[color].end(),r)-pos[color].begin()-1;
24         return r-l+1;
25     }inline void Solve(){
26         for(int i=1;i<=n;i++)pos[a[i]].push_back(i);
27         f[1]=a[1];
28         for(int i=2;i<=n;i++)
29             for(int j=0;j<i;j++)
30                 f[i]=max(f[i],f[j]+sqr(Count(a[j+1],j+1,i))*a[j+1]);
31         cout<<f[n]<<endl;
32     }
33 }
34 namespace Solution_2{
35     int f[M],c[M],top,lst[M];vector<int>sta[10005];
36     inline double X(int i){return a[i]*c[i];}
37     inline double Y(int i){return f[i-1]+a[i]*sqr(c[i]-1);}
38     inline double Slope(int i,int j){return (Y(i)-Y(j))/(X(i)-X(j));}
39     inline int calc(int i,int j){return f[j-1]+sqr(c[i]-c[j]+1)*a[i];}
40     #define A sta[a[i]][sta[a[i]].size()-2]
41     #define B sta[a[i]][sta[a[i]].size()-1]
42     inline void Solve(){
43         for(int i=1;i<=n;i++)c[i]=c[lst[a[i]]]+1,lst[a[i]]=i;
44         for(int i=1;i<=n;i++){
45             while(sta[a[i]].size()>=2&&Slope(A,i)>=Slope(A,B))sta[a[i]].pop_back();
46             sta[a[i]].push_back(i);
47             while(sta[a[i]].size()>=2&&calc(i,B)<=calc(i,A))sta[a[i]].pop_back();
48             f[i]=calc(i,sta[a[i]].back());
49         }cout<<f[n]<<endl;
50     }
51 }
52 signed main(){
53     n=read();
54     for(int i=1;i<=n;i++)a[i]=read();
55     if(n<=1000)Solution_1::Solve();
56     else Solution_2::Solve();
57     return 0;
58 }
相關文章
相關標籤/搜索