Educational Codeforces Round 42 E 贪心

题目链接


题意:
数轴上有三种类型的点:B型点、R型点、P型点。
你可以连接任意两个点,连接的代价是两个点的距离,即坐标之差。
而最终希望达到的条件是:
如果去除所有B型点,R型点和P型点中任意两个点连通。
如果去除所有R型点,B型点和P型点中任意两个点连通。

现在给定n个点的坐标和类型,求满足条件的最小代价。


思路:

首先有一个显然合法的可行方案:
即先单独考虑所有B型点和P型点,相邻的两个点连边,最终代价为最右边的点(B/P)和最左边的点(B/P)的距离。
随后单独考虑所有R型点和P型点,分析同上。

可是考虑一个特殊情况,有四个点,从左到右的坐标及类型为:
P(0) 、 B(1) 、 R(99) 、 P(100)

对于上面的方案,代价显然是: A n s = ( 100 0 ) + ( 100 0 ) = 200
而更好的选择是:将两个P点连接起来,随后B点连接左边的P点,R点连接右边的P点,此时代价为:
A n s = ( 100 0 ) + ( 1 0 ) + ( 100 99 ) = 102

可以发现:
如果将两个相邻的P点连接起来,从而B型点和R型点连接时均可以共用这一条边,此时可能会让总代价变得更小。

故我们可以先按第一个方案算出一个初步的总代价 A n s
随后按坐标从左到右枚举两个相邻的P点:
而对于原来按第一种方案连接的结构,比如当考虑B型点和P型点时,连接是:

P 0 B 0 B 1 B 2 . . . B t P 1

而此时因为 P 0 P 1 已经连接,故中间有一条边可以断开不连,由贪心的思想显然断开的边越长越好,假设对于该情况,断开的边最长长度为 F u n ( B )

同理,可以求出 F u n ( R )

则对于两个相邻P点构成的子区间,此时需要付出的总代价为:(假设 L e n = P 1 P 0 )

S u m 1 = L e n + ( L e n F u n ( B ) ) + ( L e n F u n ( R ) ) = 3 L e n F u n ( B ) F u n ( R )

而原来需要付出的总代价为:

S u m 2 = L e n + L e n = 2 L e n

故对于原来得到的初步总代价 A n s ,我们可以更新为:

A n s = S u m 2 S u m 1

此题得解。


代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;

char s[100+10];
vector<int> vR,vB,vP;

ll Fun(const vector<int>& v,int l,int r){
    int st = lower_bound(v.begin(),v.end(),l) - v.begin();
    int ed = lower_bound(v.begin(),v.end(),r) - v.begin();

    ll res = 0;
    for(int i=st ;i<ed ;i++) res = max(res,1LL*v[i+1]-1LL*v[i]);
    return res;
}

int main(){
    int n;scanf("%d",&n);

    for(int i=1 ;i<=n ;i++){
        int x;
        scanf("%d%s",&x,s);

        if(s[0] == 'R')         vR.push_back(x);
        else if(s[0] == 'B')    vB.push_back(x);
        else{
            vR.push_back(x);
            vB.push_back(x);
            vP.push_back(x);
        }
    }
    sort(vR.begin(),vR.end());
    sort(vB.begin(),vB.end());
    sort(vP.begin(),vP.end());

    ll ans = 0;
    if(vR.size() > 1) ans += vR[vR.size()-1] - vR[0];
    if(vB.size() > 1) ans += vB[vB.size()-1] - vB[0];

    int Siz = vP.size();
    for(int i=0 ;i<Siz-1 ;i++){
        int l = vP[i],r = vP[i+1];
        ans -= max(0LL,Fun(vB,l,r) + Fun(vR,l,r) - 1LL*(r-l));
    }
    printf("%I64d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wubaizhe/article/details/79894379