题目链接:https://nanti.jisuanke.com/t/42404
题目大意:
a[i]表示对手的每个队伍战斗力
p[i]表示打败对手后获得的声望
b[i]表示我方第一种人的战斗力
c[i]表示我方第二种人的战斗力
定义我方一组选手的战斗力为b[i]+c[j],第一种选手与第二种选手某种顺序两两组队后,与对方进行pk,共有n!种pk顺序,你选择最佳的匹配方案,求能够获得最大期望声望×n。
思路:
我们假设b[i]和c[j]和组队,那么题目和对手然后一个打都是等可能的。能够获得的声望的期望为b[i]+c[j]>a[k]。的所有的p[k]的和/n。那么就可以把b[i]和c[j]建边直接跑KM。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long long LL;
const int N=405;
const ll INF=0x3f3f3f3f3f3f3f3f;
struct KuhnMunkres {
int n;//左右集合点数max(ln, rn)
ll a[N][N];
ll hl[N],hr[N],slk[N];//hl hr 左边集合的期望值,右边集合的期望值
int fl[N],fr[N],vl[N],vr[N],pre[N],q[N],ql,qr;//fl fr,左右匹配对应的点 vl,vr用于bfs标记,
int check(int i) {
if(vl[i]=1,fl[i]!=-1)
return vr[q[qr++]=fl[i]]=1;
while(i!=-1)
swap(i,fr[fl[i]=pre[i]]);
return 0;
}
void bfs(int s) {
memset(slk,0x3f,sizeof(slk));
memset(vl,0,sizeof(vl));
memset(vr,0,sizeof(vr));
q[ql=0]=s;
vr[s]=qr=1;
for(ll d;;) {
for(; ql<qr; ++ql)
for(int i=0,j=q[ql]; i<n; ++i)
if(d=hl[i]+hr[j]-a[i][j],!vl[i]&&slk[i]>=d)
if(pre[i]=j,d)
slk[i]=d;
else if(!check(i))
return;
d=INF;
for(int i=0; i<n; ++i)
if(!vl[i]&&d>slk[i])
d=slk[i];
for(int i=0; i<n; ++i) {
if(vl[i])
hl[i]+=d;
else
slk[i]-=d;
if(vr[i])
hr[i]-=d;
}
for(int i=0; i<n; ++i)
if(!vl[i]&&!slk[i]&&!check(i))
return;
}
}
ll ask(int nl, int nr) {
n=max(nl,nr);
memset(pre,-1,sizeof(pre));
memset(fl,-1,sizeof(fl));
memset(fr,-1,sizeof(fr));
memset(hr,0,sizeof(hr));
for(int i=0; i<n; ++i)
hl[i]=*max_element(a[i],a[i]+n);
for(int j=0; j<n; ++j)
bfs(j);
long long ans=0;
for(int i=0; i<n; ++i)
ans+=a[i][fl[i]];
return ans;
}
} km;
typedef struct node
{
ll num;
int val;
}node;
bool cmp(node a,node b)
{
return a.num<b.num;
}
ll b[405],c[405];
ll d[405];
int sum[405];
node a[405];
int main()
{
int n; scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i].num);
}
for(int i=1;i<=n;i++){
scanf("%d",&a[i].val);
}
for(int i=1;i<=n;i++){
scanf("%lld",&b[i]);
}
for(int i=1;i<=n;i++){
scanf("%lld",&c[i]);
}
sort(b+1,b+1+n);
sort(c+1,c+1+n);
sort(a+1,a+1+n,cmp);
sum[0]=0;
for(int i=1;i<=n;i++) {
sum[i] = sum[i - 1] + a[i].val;
d[i]=a[i].num;
}
for(int i=1;i<=n;i++){
int last=1;
for(int j=1;j<=n;j++){
ll val = b[i] + c[j];
while(d[last] < val&&last<=n) last++;
//if(!sum[last-1]) continue;
km.a[i-1][j-1]=sum[last-1];
}
}
printf("%d\n",km.ask(n, n));
return 0;
} 
京公网安备 11010502036488号