CF1043E Train Hard, Win Easy

一、题目

点此看题

二、解法

建议多读几遍题,读懂了之后会发现暴力算法是 O ( n 2 ) O(n^2)

考虑选取的条件,假设应该选取 i i 做第一道题, j j 做第二道题:
x i + y j < y i + x j x_i+y_j<y_i+x_j x i y i < x j + y j x_i-y_i<x_j+y_j 你会发现这样选取的条件就取决于 i i 它自身了,我们可以把所有人按 x y x-y 排序,然后枚举 i i ,在 i i 之前的让 i i 做第二道题,否则 i i 做第一道题,这样用一个前缀和就可以统计了,那个 m m 对限制直接暴力删去贡献,不是难点。

这应该算是贪心优化统计吧,时间复杂度 O ( n log n ) O(n\log n) ,贴个代码。

#include <cstdio>
#include <algorithm>
using namespace std;
#define int long long
const int M = 300005;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,m,tot,ans[M],f[M],p1[M],p2[M];
struct edge
{
    int v,next;
    edge(int V=0,int N=0) : v(V) , next(N) {}
}e[2*M];
struct node
{
    int x,y,id;
    node(int X=0,int Y=0) : x(X) , y(Y) {}
    bool operator < (const node &R) const
    {
        return x-y<R.x-R.y;
    }
}a[M];
signed main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        a[i].x=read(),a[i].y=read(),a[i].id=i;
    for(int i=1;i<=m;i++)
    {
        int u=read(),v=read(),c=min(a[u].x+a[v].y,a[u].y+a[v].x);
        e[++tot]=edge(c,f[u]),f[u]=tot;
        e[++tot]=edge(c,f[v]),f[v]=tot;
    }
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++)
    {
        p1[i]=p1[i-1]+a[i].x;
        p2[i]=p2[i-1]+a[i].y;
    }
    for(int i=1;i<=n;i++)
    {
        int id=a[i].id;
        ans[id]=p1[i-1]+p2[n]-p2[i]+(i-1)*a[i].y+(n-i)*a[i].x;
        for(int j=f[id];j;j=e[j].next)
            ans[id]-=e[j].v;
    }
    for(int i=1;i<=n;i++)
        printf("%lld ",ans[i]);
}
发布了257 篇原创文章 · 获赞 13 · 访问量 6743

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/104124650