CF631E 题解
CF631E Product Sum
- 斜率优化DP
- *2600
闲话
模拟赛 D 题。感觉是个斜优的比较板的题。
开始写了一发错误的贪心,Wa on 9,后来改成 DP 才过。
场上过了
题意
给定一个长度为
解析
先考虑 naive 做法。对于每个
具体地,分两种情况讨论。对于向前移动,即
也就是
对于向后移动,移动到位置
尝试化简一下第一个式子。
我们推导可以发现,向前移动与向后移动的式子等价。这样的话,两个转移被合并成了一个转移,方便很多。
我们还需要优化。把括号拆开,变成
数据没有单调性,所以可以用二分凸包或者李超树维护。
代码实现
考场上没想到可以变一个式子,正反做了两遍,二分+栈。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define db double
#define endl '\n'
#define pii pair<int,int>
#define eb emplace_back
#define F(i,x,y) for(int i=(x);i<=(y);++i)
#define fo(i,x,y) for(int i=(x);i>=(y);--i)
constexpr int N=2e5+10;
constexpr int M=5e5+10;
constexpr int mod=1e9+7;
constexpr int inf=0x3f3f3f3f;
constexpr ll INF=0x3f3f3f3f3f3f3f3f;
constexpr db eps=1e-8;
#define int long long
int a[N],f[N];
struct line{
int k,b;
line(){}
line(int _k,int _b){
k=_k,b=_b;
}
int calc(int x){
return k*x+b;
}
};
struct tree{
#define t1 s.size()-1
#define t2 s.size()-2
vector<line> s;
bool cmp(line x,line p1,line p2){
return (p2.b-x.b)*(p1.k-p2.k)<=(p2.b-p1.b)*(x.k-p2.k);
}
void insert(line x){
while(s.size()>=2&&cmp(x,s[t1],s[t2])) s.pop_back();
s.eb(x);
}
int query(int x){
int l=0,r=t1;
while(l<r){
int mid=(l+r)>>1;
if(s[mid].calc(x)>=s[mid+1].calc(x)) r=mid;
else l=mid+1;
}
return s[r].calc(x);
}
#undef t1
#undef t2
}t1,t2;
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,res=0,ans=0;
cin>>n;
F(i,1,n){
cin>>a[i];
f[i]=f[i-1]+a[i];
res+=i*a[i];
}
t1.insert(line(1,-f[0]));
F(i,2,n){
ans=max(ans,-a[i]*i+f[i-1]+t1.query(a[i]));
t1.insert(line(i,-f[i-1]));
}
t2.insert(line(-n,-f[n]));
fo(i,n-1,1){
ans=max(ans,-a[i]*i+f[i]+t2.query(-a[i]));
t2.insert(line(-i,-f[i]));
}
cout<<ans+res<<endl;
return 0;
}
赛后用李超树写了第二种实现,
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define db double
#define endl '\n'
#define pii pair<int,int>
#define eb emplace_back
#define F(i,x,y) for(int i=(x);i<=(y);++i)
#define fo(i,x,y) for(int i=(x);i>=(y);--i)
constexpr int N=2e5+10;
constexpr int M=1e6;
constexpr int mod=1e9+7;
constexpr int inf=0x3f3f3f3f;
constexpr ll INF=0x3f3f3f3f3f3f3f3f;
constexpr db eps=1e-8;
#define int long long
int k[N],b[N],s[N],a[N];
int calc(int i,int x){return k[i]*x+b[i];}
int t[M<<4];
void update(int p,int l,int r,int x){
if(l==r){
if(calc(x,l)>calc(t[p],l)) t[p]=x;
return ;
}
int mid=(l+r)>>1;
if(calc(x,mid)>calc(t[p],mid)) swap(t[p],x);
if(calc(x,l)>calc(t[p],l)) update(p<<1,l,mid,x);
else if(calc(x,r)>calc(t[p],r)) update(p<<1|1,mid+1,r,x);
}
int query(int p,int l,int r,int x){
if(l==r) return calc(t[p],x);
int mid=(l+r)>>1;
int res=calc(t[p],x);
if(x<=mid) return max(res,query(p<<1,l,mid,x));
else return max(res,query(p<<1|1,mid+1,r,x));
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,res=0,ans=0;
cin>>n;
F(i,1,n){
cin>>a[i];
res+=i*a[i];
s[i]=a[i]+s[i-1];
k[i]=i;
b[i]=-s[i];
update(1,-M,M,i);
}
F(i,1,n){
int tmp=query(1,-M,M,a[i]);
ans=max(ans,s[i]-a[i]*i+tmp);
}
cout<<ans+res<<endl;
return 0;
}
完结撒花!题解不易,望管理通过。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步