题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4709
课上讲的题,还是参考了博客...:https://www.cnblogs.com/GXZlegend/p/8615607.html
这道题和之前写的斜率优化不同的一点是用单调栈维护上凸壳,而且需要二分查找答案;
为什么感觉每次写出来的斜率优化DP都不一样...还是没有理解透彻...
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; typedef long long ll; int const maxn=1e5+5,maxm=1e4+5; int n,a[maxn]; ll s[maxn],cnt[maxm],f[maxn]; vector<int>v[maxm]; ll x(int i){return s[i]-1;} ll y(int i){return f[i-1]+a[i]*(s[i]-1)*(s[i]-1);} ll ans(int i,int j){return f[j-1]+a[i]*(s[i]-s[j]+1)*(s[i]-s[j]+1);} ll squ(ll x){return x*x;} int main() { scanf("%d ",&n); for(int i=1,j,k,t;i<=n;i++) { scanf("%d",&a[i]); s[i]=++cnt[a[i]]; while((t=v[a[i]].size()-1)>0 && (x(i)-x(j=v[a[i]][t]))*(y(k=v[a[i]][t-1])-y(j)) - (y(i)-y(j))*(x(k)-(x(j))) > 0)//别写成if v[a[i]].pop_back(); v[a[i]].push_back(i); int l=1,r=v[a[i]].size()-1,res=0;//res=0 //不取新加入的i while(l<=r) { int mid=((l+r)>>1); if(ans(i,v[a[i]][mid])>ans(i,v[a[i]][mid-1]))res=mid,l=mid+1; else r=mid-1; } f[i]=ans(i,v[a[i]][res]); } printf("%lld ",f[n]); return 0; }