Description
作为新开的水果连锁店店员,你需要把总部发给你的苹果和雪梨分组出售,从而获得最
大利润。
总部发给你的水果包括:
n 个苹果,质量分别为a1,a2…an
n 个雪梨,质量分别为b1,b2…bn。
你卖的是盒装水果,一盒水果包括一个苹果和一个雪梨,苹果的质量乘上雪梨的质量就
是这盒水果的价钱。把苹果雪梨配对分成总共n 盒水果后,你要把价格最高的一盒返还给
水果店总部,剩下n-1 盒水果价格的和就是你的利润。注意:虽然返还给水果店总部的水
果不算在你的利润里,但是你必须把价格最高的一盒水果返还给总部。
Input
第一行一个正整数n。
第二行n 个正整数表示苹果的质量a1,a2…an。
第三行n 个正整数表示雪梨的质量b1,b2…bn。
Output
一个正整数,表示除了价格最大的那盒水果外其他水果的价格和的最大值(你的利润)。
Sample Input
输入1:
3
2 3 4
2 3 4
输入2:
3
2 3 100
2 3 100
Sample Output
输出1:
16
输出2:
304
Data Constraint
对于10%的数据n<=5
对于30%的数据n<=50
对于50%的数据n<=100
对于100%的数据n<=3000, ai<=1e7 bi<=1e7
正解有点恶心。
枚举最大值,首先保证已经做过的最大值方案最优(匹配),然后对于当前最大值V,假设他的匹配为x,y那么我们可以发现:
对于x原来的匹配pos[x]和y原来的匹配`,a[x]*b[y]+a[bl[y]]*b[pos[x]]>=a[x]*b[pos[x]]+a[bl[y]]*b[pos[x]],最大值相同,所以直接消去。
那么说明每一次我们都需要对当前的匹配进行交叉互换,可以保证是最优的,否则就不能交叉互换,只有当前匹配不满足时才可以交换,否则就不是最优的。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
typedef long long ll;
struct node
{
int x,y;
ll v;
}c[9000005];
int a[N],b[N],pos[N],bl[N],n;
inline bool cmp(node a,node b)
{
if (a.v!=b.v)return a.v<b.v;
if (a.x!=b.x)return a.x<b.x;
return a.y<b.y;
}
int main()
{
freopen("fruits.in","r",stdin);
freopen("fruits.out","w",stdout);
scanf("%d\n",&n);
fo(i,1,n)scanf("%d",&a[i]);
fo(i,1,n)scanf("%d",&b[i]);
sort(a+1,a+1+n),sort(b+1,b+1+n);
int tot=0;
fo(i,1,n)
{
fo(j,1,n)
{
c[++tot].v=1ll*a[i]*b[j];
c[tot].x=i,c[tot].y=j;
}
}
sort(c+1,c+1+tot,cmp);
ll ans=0,sum=0;
fo(i,1,tot)
{
int x=c[i].x,y=c[i].y,k=bl[y];
if (k==0)
{
sum-=1ll*a[x]*b[pos[x]]-1ll*a[x]*b[y];
bl[pos[x]]=0;pos[x]=y;bl[y]=x;
}
else
{
sum-=1ll*a[x]*b[pos[x]]+1ll*a[k]*b[y];
swap(bl[y],bl[pos[x]]);
swap(pos[x],pos[k]);
sum+=1ll*a[x]*b[pos[x]]+1ll*a[k]*b[pos[k]];
bl[y]=x;
}
ans=max(ans,sum-c[i].v);
//printf("%lld\n",sum);
}
printf("%lld\n",ans);
}