CF1043E Solution

题目链接

题解

可以发现枚举两个在一组里的数会TLE,加之只有两个参数限制与数据范围,容易想到排序算法。

计算第(i)个人的分数和需要知道他在每一组里是(x)还是(y),因此排序需要满足(a_i)前的数与(a_i)组合时为(x)更优,而(a_i)后的数与(a_i)组合时为(y)更优(反之亦可),也就是(x_i+y_{i+1}<x_{i+1}+y_i)

而对于(a_i),则分数和:

[=sumlimits_{j=1}^{i-1} (x_j+y_i)+sumlimits_{j=i+1}^n(x_i+y_j)\ =sumlimits_{j=1}^{i-1} x_j+y_icdot (i-1)+sumlimits_{j=i+1}^ny_j+x_icdot (i-1) ]

两个(Sigma)用前缀和维护即可。

此外,对于不可以组队的两个数,记录它们组队时的分数,在统计答案时分别减去即可。

AC代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+10;
struct node{int x,y,id;} a[N];
bool cmp(node a,node b) {return a.x+b.y<a.y+b.x;} 
int id[N],mi[N],sumx[N],sumy[N];
//id[i]:排序前下标为i的元素排序后的下标,mi[i]:a[i]因不可在一起组队需减去的分数
signed main()
{
	int n,m,u,v;
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++) {scanf("%lld%lld",&a[i].x,&a[i].y); a[i].id=i;}
    //排序
	sort(a+1,a+n+1,cmp);
    //处理前缀和与id数组
	for(int i=1;i<=n;i++) sumx[i]=sumx[i-1]+a[i].x,sumy[i]=sumy[i-1]+a[i].y;
	for(int i=1;i<=n;i++) id[a[i].id]=i;
    //处理不可在一起组队的元素
	while(m--)
	{
		scanf("%lld%lld",&u,&v);
		if(id[u]<id[v]) mi[u]+=a[id[u]].x+a[id[v]].y,mi[v]+=a[id[u]].x+a[id[v]].y;
		else mi[u]+=a[id[u]].y+a[id[v]].x,mi[v]+=a[id[u]].y+a[id[v]].x;
	}
    //统计答案
	for(int i=1;i<=n;i++)
	{
		int t=id[i];
		printf("%lld ",sumx[t-1]+a[t].y*(t-1)+sumy[n]-sumy[t]+a[t].x*(n-t)-mi[i]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/violetholmes/p/14257469.html