题意:
有n个参赛者,每个参赛者在做第一题和第二题都有一个罚时,两个人组成一队,每个人负责一题,该队罚时为两人罚时之和(队内会取最优策略),求该参赛者在所有可能的组队中总罚时为多少?
思路:
我们发现可以按照前一个写第一题,后一个写第二题最优来排序:
既:A.a+B.b<A.b+B.a
先求该参赛者与所有其他参赛者组队的总贡献:
既:与排在自己前面的组队时取前面的第一题罚时,自己取第二题罚时。
与排在自己后面的组队时取后面的第二题罚时,自己取第一题罚时。
这过程可以用前缀和优化。
然后由于某些不能组队,所有将不能组队的贡献减去即可。
代码:
#include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <vector> #include <queue> #include <iostream> using namespace std; typedef long long ll; const ll inf=1e9+9; const int N=1000005; struct w { ll a, b, k; }w[N]; bool cmp(struct w a,struct w b) // 排序规则 { return a.a+b.b<a.b+b.a; } ll suma[N], sumb[N], ans[N]; int main() { ll n, m; scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) { scanf("%lld%lld",&w[i].a,&w[i].b); w[i].k=i; } for(int i=1;i<=m;i++) //减去不能组队的队伍的贡献。 { int x, y; scanf("%d%d",&x,&y); ll k=min(w[x].a+w[y].b,w[x].b+w[y].a); ans[x]-=k; ans[y]-=k; } sort(w+1,w+n+1,cmp); for(int i=1;i<=n;i++) //求前缀和 { suma[i]=suma[i-1]+w[i].a; sumb[i]=sumb[i-1]+w[i].b; } for(int i=1;i<=n;i++) //加上所有队伍的贡献。 { ans[w[i].k]+=suma[i-1]+(i-1)*w[i].b+sumb[n]-sumb[i]+(n-i)*w[i].a; } for(int i=1;i<=n;i++) { printf("%lld%c",ans[i],i==n?'\n':' '); } return 0; }