BZOJ[1713][Usaco2007 China]The Bovine Accordion and Banjo Orchestra 音乐会 二维斜率优化
首先\(i\)越大\(j\)越大
所以dp,\(f_{i,j}\)表示\(a_i\)和\(b_j\)配的最大获利
所以有\(f_{i,j}=max\{f_{t,k}-(sb_{j-1}-sb_{k})^2-(sa_{i-1}-sa_{t})^2\}\),其中\(sa,sb\)两数组的前缀和
又可以发现最优的转移满足\(t=i-1,k=j-1\)这两个其中之一,因为如果不满足,可以选\(a_{i-1}\)和\(b_{j-1}\)配对,答案更优
所以dp方程式可以表示为\(f_{i,j}=max\{f_{i-1,t}-(sb_{j-1}-sb_t)^2,f_{k,j-1}-(sa_{i-1}-sa_k)^2\}\)
现在两种转移分开考虑,化简,得到\(t\)比\(k\)优的情况,满足
\[\frac{g_t-g_k}{sb_t-sb_k}>-2sb_{j-1}\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,①
$$\]
\frac{g_t-g_k}{sa_t-sa_k}>-2sa_{i-1},,,,,,,,,,,,,,,,,,,,,,②
\[其中①中的$g_t=f_{i-1,t}-sb_t^2$,②中的$g_t=f_{t,j-1}-sa_t^2$
维护两个上凸壳,搞一个二维的斜率优化就可以了
代码略(特别)丑
代码如下:
```cpp
#include<algorithm>
#include<ctype.h>
#include<cstdio>
#define INF 21474836470000ll
#define N 1050
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;
int n,l,r;
int a[N],b[N],ly[N],ry[N];
LL ans;
LL sa[N],sb[N],f[N][N];
struct Point{
LL x,y;
Point(){}
Point(LL _,LL __):x(_),y(__){}
}qi[N],qj[N][N],tmp;
inline double Slope(Point a,Point b){
if(a.x==b.x) return a.y>b.y?-INF:INF;
return 1.0*(b.y-a.y)/(b.x-a.x);
}
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
sa[i]=sa[i-1]+a[i];
}
for(int i=1;i<=n;i++){
b[i]=read();
sb[i]=sb[i-1]+b[i];
}
for(int i=1;i<=n;i++)
ly[i]=1;
for(int i=1;i<=n;i++){
l=1;r=0;
for(int j=1;j<=n;j++){
f[i][j]=a[i]*b[j]-sa[i-1]*sa[i-1]-sb[j-1]*sb[j-1];
while(l<r && Slope(qi[l],qi[l+1])>-sb[j-1]*2)
l++;
if(i>0 && l<=r)
f[i][j]=max(f[i][j],qi[l].y+sb[j-1]*2*qi[l].x-sb[j-1]*sb[j-1]+1ll*a[i]*b[j]);
/////上面是从i-1转移
while(ly[j]<ry[j] && Slope(qj[j][ly[j]],qj[j][ly[j]+1])>-sa[i-1]*2)
ly[j]++;
if(j>0 && ly[j]<=ry[j])
f[i][j]=max(f[i][j],qj[j][ly[j]].y+sa[i-1]*2*qj[j][ly[j]].x-sa[i-1]*sa[i-1]+1ll*a[i]*b[j]);
/////从j-1转移
if(i-1){
tmp=Point(sb[j],f[i-1][j]-sb[j]*sb[j]);
while(l<r && Slope(qi[r],tmp)>Slope(qi[r-1],qi[r]))
r--;
if(i-1) qi[++r]=tmp;
}
///上下全是更新队列
if(j-1){
tmp=Point(sa[i],f[i][j-1]-sa[i]*sa[i]);
while(ly[j]<ry[j] && Slope(qj[j][ry[j]],tmp)>Slope(qj[j][ry[j]-1],qj[j][ry[j]]))
ry[j]--;
qj[j][++ry[j]]=tmp;
}
}
}
for(int i=1;i<=n;i++)
ans=max(ans,max(f[i][n]-(sa[n]-sa[i])*(sa[n]-sa[i]),f[n][i]-(sb[n]-sb[i])*(sb[n]-sb[i])));
printf("%lld",ans);
return 0;
}
```\]