BZOJ[4709][Jsoi2011]柠檬 斜率优化

传送门ber~
容易发现选的每一段左右一定是同色…
那么有 f i = m a x { f j 1 + ( s i s j + 1 ) 2 a i }
其中 i , j 同色
若存在 k > t 且答案更优,即

f k 1 + ( s i s k + 1 ) 2 a i > f t 1 + ( s i s t + 1 ) 2 a i

f k 1 f t 1 > a i ( s i 2 + s t 2 + 1 2 s i s t 2 s t + 2 s i ( s i 2 + s k 2 + 1 2 s i s k 2 s k + 2 s i ) )

f k 1 f t 1 > a i ( s t 2 2 s i s t 2 s t s k 2 + 2 s i s k + 2 s k )

f k 1 f t 1 > p s t 2 2 p s i s t 2 p s t p s k 2 + 2 p s i s k + 2 p s k

f k 1 f t 1 + p s k 2 p s t 2 2 p s k + 2 p s t > s i ( 2 p s k 2 p s t )

f k 1 f t 1 + p s k 2 p s t 2 2 p s k + 2 p s t 2 p s k 2 p s t > s i

y = f k 1 + p s k 2 2 p s k
x = 2 p s k
f k 1 + p s i 2 + p s k 2 + p 2 p s i s k 2 p s k + 2 p s i
= y x s i + p s i 2 + p + 2 p s i
斜率优化
单调栈
代码如下·:

#include<algorithm>
#include<cstring>
#include<ctype.h>
#include<cstdio>
#include<vector>
#define int long long
#define INF 2147483647
#define N 100020
using namespace std;
inline int read(){
    int x=0,f=1;char c;
    do c=getchar(),f=c=='-'?-1:f; while(!isdigit(c));
    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
    return x*f;
}
typedef long long LL;
struct Data{
    LL x,y;
    Data(){}
    Data(LL x,LL y):x(x),y(y){}
}tmp;
vector<Data>s[N];
int n,x,y,p,ans;
int cnt[N],pos[N],a[N],pre[N],top[N],f[N];
inline double Slope(Data a,Data b){
    if(a.x==b.x) return a.y>b.y?-INF:INF;
    return 1.0*(b.y-a.y)/(b.x-a.x);
}
 main(){
    n=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
        pre[i]=pos[a[i]];
        pos[a[i]]=i;
        cnt[i]=cnt[pre[i]]+1;
    }
    memset(pos,0,sizeof pos);
    for(int i=1;i<=n;++i)
        if(!pos[a[i]])
            s[a[i]].push_back(Data(0,0)),pos[a[i]]=1;
    for(int i=1;i<=n;i++){
        p=a[i];
        tmp=Data(2*p*cnt[i],f[i-1]+p*cnt[i]*cnt[i]-2*p*cnt[i]);
        while(top[p]>1 && Slope(s[p][top[p]-1],s[p][top[p]])<=Slope(s[p][top[p]],tmp)) top[p]--,s[p].pop_back();
        top[p]++;s[p].push_back(tmp);
        while(top[p]>1 && Slope(s[p][top[p]-1],s[p][top[p]])<=cnt[i]) top[p]--,s[p].pop_back();
        x=s[p][top[p]].x;y=s[p][top[p]].y;
        f[i]=y-x*cnt[i]+p*cnt[i]*cnt[i]+p+2*p*cnt[i];
        ans=max(ans,f[i]);
    }
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/waduan2/article/details/80882755
今日推荐