BZOJ_1713_[Usaco2007 China]The Bovine Accordion and Banjo Orchestra 音乐会_斜率优化

BZOJ_1713_[Usaco2007 China]The Bovine Accordion and Banjo Orchestra 音乐会_斜率优化

Description

Input

  第1行输入N,之后N行输入Ai,之后N行输入Bi.

Output

  输出最大收益.

Sample Input

3
1
1
5
5
1
1

INPUT DETAILS:

There are 6 cows: 3 accordionists and 3 banjoists. The accordionists have
talent levels (1, 1, 5), and the banjoists have talent levels (5, 1, 1).

Sample Output

17

HINT

 手风琴手3和班卓琴手1搭配,创造收益25美元.手风琴手1和手风琴手2喝酒用了4美元.同样班卓琴手2和班卓琴手3用了4美元.最后收益为25 -4-4=17美元

 


 

设F[i][j]表示手风琴手匹配到第i个,班卓琴手匹配到第j个的最大收益。

F[i][j]=F[k][l]+A[i]*B[j]-(sa[i-1]-sa[k])^2-(sb[j-1]-sb[l])^2。

因为A[i]*B[j]一定是正的,所以选的越多越好。

转移只有两个是有用的,F[i][j]从F[i-1][k]和F[k][j-1]转移。

斜率优化即可。注意L和R都要用数组来保存,Q也要开成二维的。

两个队列分别存i和j。

 

代码:

 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef double f2;
typedef long long ll;
#define N 1050
#define eps 1e-6
int a[N],b[N],n,l1[N],r1[N],l2[N],r2[N];
ll sa[N],sb[N],ans,f[N][N];
f2 gK(ll x,ll y,ll z,ll w) {
	if(z==x) return w>y?1e10:-1e10;
	return (1.0*w-y)/(z-x);
}
struct Point {
	ll x,y;
	int k;
}Q1[N][N],Q2[N][N];
f2 Slp(const Point &a,const Point &b) {
	if(a.x==b.x) return b.y>a.y?1e10:-1e10;
	return 1.0*(b.y-a.y)/(b.x-a.x);
}
#define X1(k) (sb[k])
#define Y1(k,i) (f[i-1][k]-sb[k]*sb[k])
#define X2(k) (sa[k])
#define Y2(k,j) (f[k][j-1]-sa[k]*sa[k])
int main() {
	scanf("%d",&n);
	int i,j,k;
	for(i=1;i<=n;i++) scanf("%d",&a[i]),sa[i]=sa[i-1]+a[i];
	for(i=1;i<=n;i++) scanf("%d",&b[i]),sb[i]=sb[i-1]+b[i];
	ans=-1ll<<60;
	for(i=1;i<=n;i++) {
		for(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(l1[i]<r1[i]-1&&Slp(Q1[i][l1[i]],Q1[i][l1[i]+1])>-2*sb[j-1]) l1[i]++;
			k=Q1[i][l1[i]].k;
			if(l1[i]<r1[i]) f[i][j]=max(f[i][j],f[i-1][k]+a[i]*b[j]-(sb[j-1]-sb[k])*(sb[j-1]-sb[k]));
			//
			while(l2[j]<r2[j]-1&&Slp(Q2[j][l2[j]],Q2[j][l2[j]+1])>-2*sa[i-1]) l2[j]++;
			k=Q2[j][l2[j]].k;
			if(l2[j]<r2[j]) f[i][j]=max(f[i][j],f[k][j-1]+a[i]*b[j]-(sa[i-1]-sa[k])*(sa[i-1]-sa[k]));

			if(i>=2) {
				Point tmp=(Point){sb[j],f[i-1][j]-sb[j]*sb[j],j};
				while(l1[i]<r1[i]-1&&Slp(Q1[i][r1[i]-1],tmp)>Slp(Q1[i][r1[i]-2],Q1[i][r1[i]-1])) r1[i]--;
				Q1[i][r1[i]++]=tmp;
			}
			if(j>=2) {
				Point tmp=(Point){sa[i],f[i][j-1]-sa[i]*sa[i],i};
				while(l2[j]<r2[j]-1&&Slp(Q2[j][r2[j]-1],tmp)>Slp(Q2[j][r2[j]-2],Q2[j][r2[j]-1])) r2[j]--;
				Q2[j][r2[j]++]=tmp;
			}
			ans=max(ans,f[i][j]-(sa[n]-sa[i])*(sa[n]-sa[i])-(sb[n]-sb[j])*(sb[n]-sb[j]));
		}
	}
	printf("%lld\n",ans);
}

 

posted @ 2018-06-28 10:01  fcwww  阅读(217)  评论(0编辑  收藏  举报