Loading

题解 CF1107G 【Vasya and Maximum Profit】

推销 膜 zhouakngyang 宝典

\(\color{black}{\texttt {z}}\color{red}{\texttt {houakngyang}}\) AK 完比赛让我来做这题。

题解:

为了方便,直接把 \(d_i\) 设为输入的 \((d_{i+1}-d_i)^2\)

直接做看不出啥我太菜了 ,只好先表示答案

\[ ans=max\{a\times (r-l+1) -\sum_{i=l}^{r}c_i-\max_{i=l}^{r-1}\{d_i\} \} \]

请注意 \(\max_{i=l}^{r-1}\{d_i\}\)\(r-1\)

显然的加一个前缀和,设 \(sc_i=\sum\limits_{j=1}^{i}c_j\)

\[ans=max\{a\times (r-l+1) -sc_{r}-sc_{l-1}-\max_{i=l}^{r-1}\{d_i\} \} \]

然后就自闭了 \(5min\)

无聊变换一下式子,

\[ans=max\{(a\times r -sc_r)-(a\times (l-1)-sc_{l-1})-\max_{i=l}^{r-1}\{d_i\} \} \]

发现除了那个 \(\max_{i=l}^{r-1}\{d_i\}\) 都很好处理,啥都能维护的亚子。

不好处理就枚举呗。

枚举以 \(d_i\) 为最大值的区间 \([lp_i,rp_i]\) ,这个可以单调栈 \(O(n)\) 搞。

由于要保证 \(i\in [l,r]\) ,那么\(l\) 一定在 \([lp_i,i]\) 内,\(r\)\([i,rp_i]\) 内。然后直接用一个可以处理静态询问区间最大值的数据结构维护一下 \(a*i-sc_i\) 即可,注意下标!

还有一种情况不需要减 \(d_i\) ,就是 \(l=r\) 的时候,枚举特判一下即可

#define int long long
inline int rd() {
    int a=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))a=a*10+(ch^48),ch=getchar();
    return a*f;
}
#define N 300009
int n,a,ans;
int c[N],sc[N],d[N];
int lg[N],pw2[25];
int st[N],top,lp[N],rp[N];
struct ST_Table {
    int st[20][N];
    void init() {
        for(int i=1;i<=19;++i)
            for(int j=1;j+pw2[i]-1<=n;++j)
                st[i][j]=max(st[i-1][j],st[i-1][j+pw2[i-1]]);
    }
    int ask(int l,int r) {
		if(l>r)return 0;
        int x=lg[r-l+1];
        return max(st[x][l],st[x][r-pw2[x]+1]);
    }
}s[2];
void st_init() {
    lg[0]=-1,pw2[0]=1;
    for(int i=1;i<N;++i)lg[i]=lg[i>>1]+1;
    for(int i=1;i<=20;++i)pw2[i]=pw2[i-1]<<1;
}
signed main() {
    n=rd(),a=rd();
    st_init();
    for(int i=1;i<=n;++i)d[i]=rd(),sc[i]=sc[i-1]+(c[i]=rd());
    for(int i=1;i<n;++i)d[i]=(d[i+1]-d[i])*(d[i+1]-d[i]);
    for(int i=1;i<n;++i) {
        while(top&&d[st[top]]<d[i])rp[st[top--]]=i-1;
        lp[i]=st[top]+1,st[++top]=i;
    }
    while(top)rp[st[top--]]=n-1;
    for(int i=1;i<=n;++i)
        s[0].st[0][i]=sc[i-1]-a*(i-1),
        s[1].st[0][i]=a*(i+1)-sc[i+1];
    s[0].init(),s[1].init();
    for(int i=1;i<=n;++i)ans=max(ans,a-c[i]);
    for(int i=1;i<n;++i)
        ans=max(ans,s[0].ask(lp[i],i)+s[1].ask(i,rp[i])-d[i]);
    printf("%lld\n",ans);
    return 0;
}
posted @ 2020-09-03 20:50  zzctommy  阅读(132)  评论(0编辑  收藏  举报