题目链接: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;
}