[APIO2010] 特别行动队 题解
前言
- 第一个不看题解自己A的紫,故写题解qwq
- msjing on 26.7.25:不是这才俩月降蓝了
solve
- 先写出朴素的转移方程
- \(f_i=f_j+get(s_i-s_j)\),其中get为\(ax^2+bx+c\)
- code
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
constexpr int maxn=1e6+10;
long long n;
long long a,b,c;
long long x[maxn];
long long s[maxn];
long long f[maxn];
long long get(int x) {return a*x*x+b*x+c;}
int main()
{
// freopen("P3628_3.in","r",stdin);
memset(f,128,sizeof(f));
f[0]=0;
cin >> n >> a >> b >> c;
for (long long i=1;i<=n;i++) cin >> x[i];
for (long long i=1;i<=n;i++) s[i]=s[i-1]+x[i];
for (long long i=1;i<=n;i++)
{
for (long long j=0;j<i;j++)
{
f[i]=max(f[i],f[j]+get(s[i]-s[j]));
}
}
cout << f[n] << endl;
return 0;
}
- 预估50实际50
- 考虑优化
- 拆开此转移方程,有:\(f_i=f_j+as_j^2-bs_j-2as_is_j+as_i^2+bs_i+c\)
- 观察发现,转移与i,j有关
- 把外层i看成定值,发现是一个线性规划问题,要维护一个上凸壳,采用斜率优化
- \(y=f_j+as_j^2-bs_j\),\(k=2as_i\),\(x=s_j\)
- k单调,用单调队列维护队头队尾,均摊O(1),可以通过
code
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
constexpr int maxn=1e6+10;
long long n;
long long a,b,c;
long long x[maxn];
long long s[maxn];
long long f[maxn];
long long q[maxn],l=1,r=1;
long long get(long long x) {return a*x*x+b*x+c;}
long long gt(long long j) {return f[j]+a*s[j]*s[j]-b*s[j];}
int main()
{
// freopen("P3628_3.in","r",stdin);
cin >> n >> a >> b >> c;
for (long long i=1;i<=n;i++) cin >> x[i];
for (long long i=1;i<=n;i++) s[i]=s[i-1]+x[i];
f[l]=0;
for (long long i=1;i<=n;i++)
{
while (l<r && gt(q[l+1])-gt(q[l])>=2*a*s[i]*(s[q[l+1]]-s[q[l]])) l++;
f[i]=f[q[l]]+get(s[i]-s[q[l]]);
while (l<r && (gt(q[r])-gt(q[r-1]))*(s[i]-s[q[r]])<=(gt(i)-gt(q[r]))*(s[q[r]]-s[q[r-1]])) r--;
q[++r]=i;
}
cout << f[n] << endl;
return 0;
}
鸣谢
wang7979
LZYXT

浙公网安备 33010602011771号