Codeforces Good Bye 2017 908F - New Year and Rainbow Roads 贪心+模拟

题目链接:
http://codeforces.com/contest/908/problem/F

F - New Year and Rainbow Roads

Roy and Biv have a set of n points on the infinite number line.

Each point has one of 3 colors: red, green, or blue.

Roy and Biv would like to connect all the points with some edges. Edges can be drawn between any of the two of the given points. The cost of an edge is equal to the distance between the two points it connects.

They want to do this in such a way that they will both see that all the points are connected (either directly or indirectly).

However, there is a catch: Roy cannot see the color red and Biv cannot see the color blue.

Therefore, they have to choose the edges in such a way that if all the red points are removed, the remaining blue and green points are connected (and similarly, if all the blue points are removed, the remaining red and green points are connected).

Help them compute the minimum cost way to choose edges to satisfy the above constraints.

Input
The first line will contain an integer n (1 ≤ n ≤ 300 000), the number of points.

The next n lines will contain two tokens pi and ci (pi is an integer, 1 ≤ pi ≤ 109, ci is a uppercase English letter ‘R’, ‘G’ or ‘B’), denoting the position of the i-th point and the color of the i-th point. ‘R’ means red, ‘G’ denotes green, and ‘B’ means blue. The positions will be in strictly increasing order.

Output
Print a single integer, the minimum cost way to solve the problem.

Examples
input
4
1 G
5 R
10 B
15 G
output
23
input
4
1 G
2 R
3 B
10 G
output
12
Note
In the first sample, it is optimal to draw edges between the points (1,2), (1,4), (3,4). These have costs 4, 14, 5, respectively.

题意:
在一条直线上有许多点,这些点有三种颜色G,R,B,给出每个点的位置及点的颜色,要求给出一种连线方式,使得所有点相连,去掉所有的R点(包括该点连的线)之后所有点仍相连,去掉所有的B点之后所有点仍相连,输出该连线方式所练线的总长度。
分析:
首先,在一条直线上把所有点相连的办法当然是按照顺序从左到右依次链接。由于R,B会被删去,所以我们通过G作为间断点,讨论每个G与G之间连接的情况。其中,G与G之间的最短连接有以下两种情况:
对于G1-R1-R2-B1-R3-B2-R4-G2
1.把G之间分别与R,B相连:代码中的2 *(x[x2]-x[x1]),即连接G1-R1-R2-R3-R4-G2以及G1-B1-B2-G2
2.把两个G相连,这时因为两个G已经连起来了,那么G-R-G那条连线可以减掉一条线,同时,G-B-G那条连线也可以减掉一条线:代码中的(x[x2]-x[x1]) * 3 - tmp1 - tmp2,此时的tmp1,tmp2分别表示减掉的那一条线。
对上述两种情况,取需要连线长度小的那一种情况。
最后讨论几种特殊情况:
1.没有G的时候,直接分别把B和R连成一条线
2.第一个G点的左边的点,B和R分别连成一条线到G,最后一个G点右边同理

预写好了一个Put函数,意思是把把要讨论的区间内B,R点都分别丢进两个vector里,这样写起来方便,这个操作也被多次用到。

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 3e5 + 5;
int x[maxn];
char type[maxn];
vector<int> R;
vector<int> B;
int szR,szB;
void Put(int st,int ed)
{
    R.clear(); B.clear();
    for(int i = st;i <= ed;i++)
    {
        if(type[i] == 1) R.push_back(i);
        else if(type[i] == 2) B.push_back(i);
    }
    szR = R.size(); szB = B.size();
}

int main()
{
    ios_base::sync_with_stdio(false); cin.tie(0);
    vector<int> G;
    int n,pos;char t;
    cin >> n;
    for(int i = 1;i <= n;i++){
        cin >> pos >> t;
        x[i] = pos;
        if(t == 'G'){
            type[i] = 0;
            G.push_back(i);
        }
        else if(t == 'R') type[i] = 1;
        else type[i] = 2;
    }
    LL ans = 0;
    int sz = G.size();
    if(sz == 0)
    {
        Put(1,n);
        if(szR > 0) ans += x[R[szR - 1]] - x[R[0]];
        if(szB > 0) ans += x[B[szB - 1]] - x[B[0]];
    }
    else{
        Put(1,G[0]-1);
        if(szR > 0) ans += (x[G[0]] - x[R[0]]);
        if(szB > 0) ans += (x[G[0]] - x[B[0]]);
        Put(G[sz - 1] + 1,n);
        if(szR > 0) ans += (x[R[szR - 1]] - x[G[sz-1]]);
        if(szB > 0) ans += (x[B[szB - 1]] - x[G[sz-1]]);
        for(int i = 0;i < sz - 1;i++){
            int x1 = G[i],x2 = G[i + 1];
            int tmp1 = 0,tmp2 = 0;
            Put(x1+1,x2-1);
            if(szR > 0){
                tmp1 = x[R[0]] - x[x1];
                for(int p = 1;p < szR;p++)
                    tmp1 = max(tmp1,x[R[p]]-x[R[p-1]]);
                tmp1 = max(tmp1,x[x2]-x[R[szR-1]]);
            }
            else tmp1 = x[x2]-x[x1];
            if(szB > 0){
                tmp2 = x[B[0]] - x[x1];
                for(int p = 1;p < szB;p++)
                    tmp2 = max(tmp2,x[B[p]]-x[B[p-1]]);
                tmp2 = max(tmp2,x[x2]-x[B[szB-1]]);
            }
            else tmp2 = x[x2]-x[x1];
            ans += min( (x[x2]-x[x1]) * 2 , (x[x2]-x[x1]) * 3 - tmp1 - tmp2 );
        }
    }
    cout << ans << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值