Codeforces 908F

题意:在一条数轴上有若干'R','B',‘G'点,连接两个点的代价是位置差,要求使用最小代价使得除去所有'R'点后剩下的所有点联通,除去所有'B'点后剩下的所有点联通。
还以为会是什么最小生成树,结果是脑洞题啊
因为G点总是要保留下来的,所以考虑按照G分成若干块,对于每个以G开头以G结尾的块,考虑如下两种操作:
1.分别依次连接 左G—中间所有的R—右G、左G—中间所有的B—右G,代价为 $ 2*len $
2.连接两端的G,再由两端的G依次分别连接中间的B和R,即,把两端的G和R、B分别依次连接,然后分别断掉最长的一段,代价为 $ 3*len-mxb-mxr $
对于每个区间分别求一下两个情况去min即可,复杂度 $ O(n) $
注意:
1.没有G的情况
2.一个区间内没有B或R的情况

#include<iostream>
#include<cstdio>
using namespace std;
const int N=300005;
int n,d[N],tot,ans;
char s[10];
struct qwe
{
	int p;
	char c;
}a[N];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%s",&a[i].p,s);
		a[i].c=s[0];
		if(s[0]=='G')
			d[++tot]=i;
	}
	if(!tot)
		d[1]=n+1;
	for(int i=1;i<d[1];i++)
		if(a[i].c=='R')
		{
			ans+=a[d[1]].p-a[i].p;
			break;
		}
	for(int i=1;i<d[1];i++)
		if(a[i].c=='B')
		{
			ans+=a[d[1]].p-a[i].p;
			break;
		}
	for(int i=n;i>d[tot];i--)
		if(a[i].c=='R')
		{
			ans+=a[i].p-a[d[tot]].p;
			break;
		}
	for(int i=n;i>d[tot];i--)
		if(a[i].c=='B')
		{
			ans+=a[i].p-a[d[tot]].p;
			break;
		}
	for(int i=1;i<tot;i++)
	{
		int prr=a[d[i]].p,prb=a[d[i]].p,mxr=0,mxb=0,len=a[d[i+1]].p-a[d[i]].p;
		for(int j=d[i]+1;j<d[i+1];j++)
			if(a[j].c=='R')
			{
				mxr=max(mxr,a[j].p-prr);
				prr=a[j].p;
			}
		for(int j=d[i]+1;j<d[i+1];j++)
			if(a[j].c=='B')
			{
				mxb=max(mxb,a[j].p-prb);
				prb=a[j].p;
			}
		if(prr!=a[d[i]].p)
			mxr=max(mxr,a[d[i+1]].p-prr);
		if(prb!=a[d[i]].p)
			mxb=max(mxb,a[d[i+1]].p-prb);
		ans+=min(2*len,(1+(mxb!=0)+(mxr!=0))*len-mxr-mxb);
	}
	cout<<ans<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/lokiii/p/8167970.html