返回顶部

Codeforces Round #519 by Botan Investments E. Train Hard, Win Easy (排序,思维)

  • 题意:有一场编程比赛,有2题\(A\)\(B\)\(n\)个人参加,每2个人组一队,每个人解决\(A\)的罚时为\(x_i\),解决\(B\)的罚时为\(y_i\),每个人只能写一题。现在还有\(m\)个关系,表示\(i\)不想和\(j\)组队,问你每个人,除了和他不想组队的人,和其他每个人组队写完两题的最小罚时之和。

  • 题解:任选两个人1和2,1写\(A\)的罚时为\(x_1\),B为\(y_1\),2写\(A\)的罚时为\(x_2\)\(B\)的罚时为\(y_2\),很明显,他们写完的总罚时要么是\(x_1+y_2\ (x_1+y_2\le x_2+y_1\ \ =>\ \ x_1-y_1\le x_2-y_2)\)要么是\(x_2+y_1\ (x_1+y_2 \ge x_2+y_1\ \ =>\ \ x_1-y_1 \ge x_2-y_2)\),那么我们根据\(x-y\)的值升序排序,排完后,在\(i\)上面的人,一定写\(A\)题最优,在\(i\)下面的人写\(B\)题最优,不懂的观察前面括号里的不等式,处理一下前缀后缀,可以\(O(1)\)算出每个人的总贡献,再减去不好的关系,然后这题基本就解决啦。

  • 代码

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    int n,m;
    struct Node{
        int x,y;
        int id;
    }a[N];
    struct misaka{
        int u,v;
    }p[N];
    ll res[N];
    ll pre[N],suf[N];
    unordered_map<int,int> mp;
    
    int main() {
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;++i){
            scanf("%d %d",&a[i].x,&a[i].y);
            a[i].id=i;
        }
        for(int i=1;i<=m;++i){
            scanf("%d %d",&p[i].u,&p[i].v);
        }
        sort(a+1,a+1+n,[&](Node _,Node __){
            return _.x-_.y<__.x-__.y;
        });
        for(int i=1;i<=n;++i){
            mp[a[i].id]=i;
        }
        for(int i=1;i<=n;++i){
            pre[i]=pre[i-1]+a[i].x;
        }
        for(int i=n;i>=1;--i){
            suf[i]=suf[i+1]+a[i].y;
            res[a[i].id]=pre[i-1]+suf[i+1]+1ll*a[i].x*(n-i)+1ll*a[i].y*(i-1);
        }
        for(int i=1;i<=m;++i){
            int u=p[i].u,v=p[i].v;
            if(mp[v]<mp[u]){
                res[u]=res[u]-a[mp[v]].x-a[mp[u]].y;
                res[v]=res[v]-a[mp[u]].y-a[mp[v]].x;
            }
            else if(mp[v]>mp[u]){
                res[u]=res[u]-a[mp[v]].y-a[mp[u]].x;
                res[v]=res[v]-a[mp[u]].x-a[mp[v]].y;
            }
        }
        for(int i=1;i<=n;++i) printf("%lld ",res[i]);
        return 0;
    }
    
    
posted @ 2021-09-25 21:39  Rayotaku  阅读(40)  评论(0编辑  收藏  举报