题链:https://nanti.jisuanke.com/t/42404
题意:给你一个n,再给出含有n个数的数组a,p,b,c。现在,你可以随意的将数组b和c中的数两两配对求和(总共有n!种配法),假设配对后的数组为d。然后再把a和d中的数两两配对比较。如果d[j]>a[i],那么可以获得p[i]单位的荣誉值,要求两两配对比较获得的荣誉值的和尽可能的大。求所能获得的荣誉值的期望乘以n,题目保证乘以n后答案为整数。
思路:我们考虑一个配对比较(d[j],a[i]),如果d[j]>a[i],那么他对期望的贡献为p[i]/(n!)。假设b[x]+c[y]==d[j],那么他俩配对的配法有(n-1)!种,所以这种情况对期望的贡献为p[i]/(n!)*(n-1)!,又因为答案要求的乘n,所以对答案的贡献就变为p[i]/(n!)*(n-1)!*n=p[i],正好为p[i]。那么对于一个d[j],它对答案的贡献为,也就是b[x]与c[y]匹配能获得的权值,问题就变成二分图最大权匹配了,不过卡dfs,所以要用bfs实现KM。另外,离散化a,再来个前缀和,就能快速求
。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 4e2+10;
const int INF = 0x3f3f3f3f;
int n,nn;
unordered_map<ll,ll> val;
ll aa[N];
ll a[N],b[N],c[N],pres[N];
int mp[N][N],slack[N],p[N];
int vis1[N],vis2[N];
int ex1[N],ex2[N];
int pre[N],link[N],lx[N],dtime,ans[N];
int q[N*2];
int head,tail;
void update(int x)
{
if(!x) return ;
link[x]=pre[x];
update(lx[pre[x]]);
lx[pre[x]]=x;
return ;
}
void bfs(int s)
{
dtime++;
int temp;
for(int i=1;i<=n;i++)
slack[i]=INF;
head=tail=0;
q[tail++]=s;
while(1)
{
while(head<tail)
{
int u=q[head++];
vis1[u]=dtime;
for(int i=1;i<=n;i++)
{
if(vis2[i]^dtime)
{
temp=ex1[u]+ex2[i]-mp[u][i];
if(!temp)
{
vis2[i]=dtime;
pre[i]=u;
if(!link[i])
{
update(i);
return ;
}
q[tail++]=link[i];
}
else if(slack[i]>temp)
{
slack[i]=temp;
pre[i]=u;
}
}
}
}
temp=INF;
for(int i=1;i<=n;i++)
if(vis2[i]^dtime&&temp>slack[i])
temp=slack[i];
for(int i=1;i<=n;i++)
{
if(vis1[i]==dtime) ex1[i]-=temp;
if(vis2[i]==dtime) ex2[i]+=temp;
else slack[i]-=temp;
}
for(int i=1;i<=n;i++)
if(vis2[i]^dtime&&!slack[i])
{
vis2[i]=dtime;
if(!link[i])
{
update(i);
return ;
}
q[tail++]=link[i];
}
}
return ;
}
void KM()
{
for(int i=1;i<=n;i++)
bfs(i);
ll res=0;
for(int i=1;i<=n;i++)
if(mp[link[i]][i])
{
res+=mp[link[i]][i];
}
printf("%lld\n",res);
return ;
}
int main(void){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),aa[i]=a[i];
for(int i=1;i<=n;i++){
scanf("%d",&p[i]);
val[a[i]]+=p[i];
}
sort(aa+1,aa+1+n);
nn=unique(aa+1,aa+1+n)-(aa+1);
pre[0]=0;
for(int i=1;i<=nn;i++)
pres[i]=pres[i-1]+val[aa[i]];
for(int i=1;i<=n;i++)
scanf("%lld",&b[i]);
for(int i=1;i<=n;i++)
scanf("%lld",&c[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
ll x=b[i]+c[j];
int pos=lower_bound(aa+1,aa+1+nn,x)-aa-1;
mp[i][j]=pres[pos];
if(mp[i][j]>ex1[i])
ex1[i]=mp[i][j];
}
KM();
return 0;
}