CF631E Product Sum

CF631E Product Sum

由于位移有两种方向,分情况讨论。记 \(S_i\) 表示 \(\sum_{i=1}^n A_i\)

  • 当把 \(A_i\) 放到 \(j\) 位置前满足 \(i \le j \le n\),则此时序列的增加的价值为 \(A_i\times(j-i)-\sum_{k=i+1}^{j} A_k=A_i\times(j-i)-S_j+S_i\)
  • 当把 \(A_i\) 放到 \(j\) 位置前满足 \(i > j \ge 0\),则此时序列增加的价值为 \(\sum_{k=j+1}^{i}A_k-A_i\times (i-j)=S_i-S_j-A_i\times(i-j)\)

观察可得上面两个式子时一样的,故无需讨论 \(i\)\(j\) 原先的位置关系。

直接 \(\text{dp}\) 可以得到时间复杂度 \(\mathcal{O}(n^2)\) 的做法,无法通过。


观察到 \(A_i \times (j-i)\),考虑斜率优化。

原式可以化为 \(A_i\times j-A_i\times i-S_j+S_i\)

由于完全与 \(i\) 有关的部分是定值,则只需要考虑 \(A_i\times j-S_j\)。将 \(j\) 看作 \(k\),将 \(A_i\) 看作 \(x\),将 \(S_j\) 看作 \(b\),即可得到直线表达式。直接使用李超线段树维护即可。

由于对于 \(i\) 来说,任意一个 \(j\) 都是合法的,所以需要先将所有直线表达式插入李超线段树而后在得到每个位置对应的答案。

时间复杂度为 \(\mathcal{O}(n \log n)\)

code
#include<bits/stdc++.h>
using namespace std;
namespace IO{
	template<typename T>inline bool read(T &x){
		x=0;
		char ch=getchar();
		bool flag=0,ret=0;
		while(ch<'0'||ch>'9') flag=flag||(ch=='-'),ch=getchar();
		while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(),ret=1;
		x=flag?-x:x;
        return ret;
	}
	template<typename T,typename ...Args>inline bool read(T& a,Args& ...args){
	    return read(a)&&read(args...);
	}
	template<typename T>void prt(T x){
		if(x>9) prt(x/10);
		putchar(x%10+'0');
	}
	template<typename T>inline void put(T x){
		if(x<0) putchar('-'),x=-x;
		prt(x);
	}
	template<typename T>inline void put(char ch,T x){
		if(x<0) putchar('-'),x=-x;
		prt(x);
		putchar(ch);
	}
	template<typename T,typename ...Args>inline void put(T a,Args ...args){
	    put(a);
		put(args...);
	}
	template<typename T,typename ...Args>inline void put(const char ch,T a,Args ...args){
	    put(ch,a);
		put(ch,args...);
	}
	inline void put(string s){
		for(int i=0,sz=s.length();i<sz;i++) putchar(s[i]);
	}
	inline void put(const char* s){
		for(int i=0,sz=strlen(s);i<sz;i++) putchar(s[i]);
	}
}
using namespace IO;
#define ll long long
#define N 200005
#define M 4000055
#define K 1000000
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
struct line{
	int k;
	ll b;
}l[N];
ll pre[N],ans;
int n,cnt,a[N],s[M<<2];
inline int add(int k,ll b){
	l[++cnt]=(line){k,b};
	return cnt;
}
inline ll calc(int id,ll x){
	return x*l[id].k+l[id].b;
}
inline void update(int x,int l,int r,int k){
	if(!s[x]) return s[x]=k,void();
	int mid=l+r>>1;
	if(calc(s[x],mid)<calc(k,mid)) swap(s[x],k);
	if(calc(s[x],l)<calc(k,l)) update(lc(x),l,mid,k);
	if(calc(s[x],r)<calc(k,r)) update(rc(x),mid+1,r,k);
}
inline ll query(int x,int l,int r,int pos){
	if(!s[x]) return -0x3f3f3f3f3f3f3f3f;
	int mid=l+r>>1;
	ll res=calc(s[x],pos);
	if(pos<=mid) res=max(res,query(lc(x),l,mid,pos));
	else res=max(res,query(rc(x),mid+1,r,pos));
	return res;
}
int main(){
	read(n);
	for(int i=1;i<=n;i++) read(a[i]),pre[i]=pre[i-1]+a[i];
	for(int i=0;i<=n;i++) update(1,-K,K,add(i,-pre[i]));
	for(int i=1;i<=n;i++)
		ans=max(ans,query(1,-K,K,a[i])-(ll)a[i]*i+pre[i]);
	for(int i=1;i<=n;i++) ans+=(ll)i*a[i];
	put('\n',ans);
	return 0;
}
posted @ 2022-10-06 15:21  fzj2007  阅读(26)  评论(0编辑  收藏  举报