2019 ICPC 南京 J . Spy

题目大意:

  a[i]表示对手的每个队伍战斗力

  p[i]表示打败对手后获得的分数

  b[i]表示我方第一种人的战斗力

  c[i]表示我方第二种人的战斗力

  定义我方一组选手的战斗力为b[i]+c[j],第一种选手与第二种选手某种顺序两两组队后,与对方进行pk,共有$n!$种pk顺序,求最大期望×n

 

题解:

  显然求我方b[i]+c[j]的方案,使得期望最大。

  考虑两两组队会和对方n个队各pk一场,故贡献即为对方战斗力小于己方的价值

  $n^{3}$预处理b[i]+c[j]的贡献,然后KM求最大带权匹配即可

  写这个题的意义在于之前并不会$n^{3}$的KM,现场费用流各种优化tle,以及网上部分KM板子有问题,故留一下板子。

 

#include <bits/stdc++.h>

using namespace std;
#define LL long long
#define ULL unsigned long long
inline LL read(){
    LL x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
#define INF 0x3f3f3f3f3f3f3f3f
#define NPOS -1
#define MAXN 500
int n;
LL g[MAXN][MAXN],hl[MAXN],hr[MAXN],slk[MAXN];
int fl[MAXN],fr[MAXN],pre[MAXN],vl[MAXN],vr[MAXN],q[MAXN],ql,qr;
LL a[MAXN],b[MAXN],p[MAXN],c[MAXN];

inline int check(int i){
    vl[i]=1;
    if (fl[i]!=NPOS){
        q[qr++]=fl[i]; vr[fl[i]]=1;
        return 1;
    }
    while (i!=NPOS){
        fl[i]=pre[i];
        swap(i,fr[fl[i]]);
    }
    return 0;
}

void bfs(int s){
    for (int i=1; i<=n; i++) vl[i]=vr[i]=0,slk[i]=INF;
    for (vr[q[ql = 0] = s] = qr = 1; ;){
        for (LL d ; ql < qr; ){
            for (int i=1,j=q[ql++]; i<=n; i++){
                if (!vl[i] && slk[i] >= (d = hl[i]+hr[j] - g[i][j]) ){
                    pre[i]=j;
                    if (d) slk[i]=d;
                    else if (!check(i)) return;
                }
            }
        }
        LL d = INF;
        for (int i=1; i<=n; i++){
            if (!vl[i] && d > slk[i]) d= slk[i];    
        }
        for (int i=1; i<=n; i++){
            if (vl[i]) hl[i] +=d;
            else slk[i] -=d;
            if (vr[i]) hr[i] -=d;
        }
        for (int i=1; i<=n; i++)
            if (!vl[i] && !slk[i] && !check(i)) return;
    }
}

LL solve(){
    for (int i=1; i<=n; i++) fl[i]=fr[i]=NPOS,hr[i]=0;
    for (int i=1; i<=n; i++) hl[i]=*max_element(g[i]+1,g[i]+n+1);
    for (int j=1; j<=n; j++) bfs(j);
    LL re = 0;
    for (int i=1; i<=n; i++) if (g[i][fl[i]]) re+=g[i][fl[i]];    
    else fl[i]=0;
    return re;
}
int main(){
    n=read();
    for (int i=1; i<=n; i++) a[i]=read();
    for (int i=1; i<=n; i++) p[i]=read();
    for (int i=1; i<=n; i++) b[i]=read();
    for (int i=1; i<=n; i++) c[i]=read();
    for (int i=1; i<=n; i++){
        for (int j=1; j<=n; j++){
            LL v = b[i]+c[j];
            for (int k=1; k<=n; k++) if (a[k]<v) g[i][j]+=p[k];
        }
    }
    LL ans = solve();
    printf("%lld\n",ans);
    return 0;
}

/*
4
1 2 3 4
1 1 1 1
0 0 1 1
0 1 1 2
*/
KM
posted @ 2020-01-11 15:58  DaD3zZ  阅读(342)  评论(2编辑  收藏