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; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮