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\),则分数和:

\[=\sum\limits_{j=1}^{i-1} (x_j+y_i)+\sum\limits_{j=i+1}^n(x_i+y_j)\\ =\sum\limits_{j=1}^{i-1} x_j+y_i\cdot (i-1)+\sum\limits_{j=i+1}^ny_j+x_i\cdot (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;
}
posted @ 2021-01-10 10:13  violet_holmes  阅读(54)  评论(0编辑  收藏  举报