CF 908F New Year and Rainbow Roads 思维,贪心,联通

题意:x轴上有n个点,分别有三种颜色(BRP),两点之间连边的代价为其距离.
要求删除红色点R时,BP中的任意两点能联通.
要求删除蓝色点B时,RP中的任意两点能联通.
n<=2e5, -1e9<=x[i]<=1e9. 问满足以上条件的最小建边代价?


若没有P点 则连接相邻的B,和连接相邻的R即可.


例子:RPR 显然这连接R-P-R,比[R-R,R-P]来的优
先将在第一个P之前的相邻点依次连接,在最后一个P后面的相邻点依次连接.
然后相邻两个P之间的情况可以独立来考虑,P....P,  先考虑B,然后R也类似考虑.


情况1:相邻的P不连接,分别连接相邻的B,BP即可.
情况2: 连接相邻的P,  P.b[1],b[2],...b[i]...b[k],P 总共k+2个点 边肯定都是相邻的.

要联通只需要k+1条边.所以去掉相邻间距最大的一条边即可.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+5;
ll n,x;
char op[2];
struct node{
	ll x;
	char op;
}a[N]; 
ll res=0;
void calc()
{
	ll mxR=-2e9,mxB=-2e9,mnR=2e9,mnB=2e9; 
	for(int j=1;j<=n;j++)
	{
		if(a[j].op=='R')
			mxR=max(mxR,a[j].x),mnR=min(mnR,a[j].x);
		if(a[j].op=='B')
			mxB=max(mxB,a[j].x),mnB=min(mnB,a[j].x);
	}
	if(mxR!=-2e9)
		res+=mxR-mnR;
	if(mxB!=-2e9)
		res+=mxB-mnB;
	cout<<res<<'\n'; 
	exit(0);
}
int main()
{
	scanf("%I64d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%I64d%s",&a[i].x,op);
		a[i].op=op[0];
	}	
	int st=-1,ed=-1;
	for(int i=1;i<=n;i++)
		if(a[i].op=='P')
		{
			ll mnR=2e9,mnB=2e9; 
			for(int j=1;j<i;j++)
			{
				if(a[j].op=='R') mnR=min(mnR,a[j].x);
				if(a[j].op=='B') mnB=min(mnB,a[j].x);
			}
			if(mnR!=2e9)
				res+=a[i].x-mnR;
			if(mnB!=2e9)
				res+=a[i].x-mnB;
			st=i;
			break;
		}
	if(st==-1)
		calc();
	for(int i=n;i>=1;i--)
		if(a[i].op=='P')
		{	
			ll mxR=-2e9,mxB=-2e9;
			for(int j=i+1;j<=n;j++)
			{
				if(a[j].op=='R')	mxR=max(mxR,a[j].x);
				if(a[j].op=='B')	mxB=max(mxB,a[j].x);
			}
			if(mxR!=-2e9)
				res+=mxR-a[i].x; 
			if(mxB!=-2e9)
				res+=mxB-a[i].x;
			ed=i;
			break; 
		}
	for(int i=st,j=i;i!=ed;i=j)
	{
		j++; 
		while(j<=n&&a[j].op!='P')
			j++;
		ll mn=1e18,sum=0; 
		ll pr=a[i].x,pb=a[i].x,mr=0,mb=0;
		for(int k=i;k<j;k++)
		{
			if(a[k].op=='R')
			{
				mr=max(mr,a[k].x-pr);
				pr=a[k].x;
			}
			if(a[k].op=='B')
			{
				mb=max(mb,a[k].x-pb);
				pb=a[k].x;
			}
		}
		if(pb!=a[i].x)
			mb=max(mb,a[j].x-pb),sum+=a[j].x-a[i].x-mb;
		if(pr!=a[i].x)
			mr=max(mr,a[j].x-pr),sum+=a[j].x-a[i].x-mr;
		if(pb!=a[i].x&&pr!=a[i].x)
			mn=min(mn,2ll*(a[j].x-a[i].x));
		sum+=a[j].x-a[i].x;
		mn=min(mn,sum);
		res+=mn;		
	}
	cout<<res<<'\n';
	return 0;
} 

每个B和R不会越过P连边 所以遇到p时可以把当前p位置当做最后一个B和R来看待,大大简化的代码量

#include<bits/stdc++.h>
#define MAXN 300005
#define INF 1000000000
#define MOD 1000000007
#define F first
#define S second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
ll n,x,lastr,lastb,lastp,mr,mb,ans=0;
char ch;
int main()
{
	scanf("%I64d",&n);
	bool pp=false,bb=false,rr=false;
	for(ll i=1;i<=n;i++)
	{
		scanf("%I64d %c",&x,&ch);
		if(ch=='R'||ch=='P')
		{
			if(rr)
			{
				ans+=x-lastr;
				mr=max(mr,x-lastr);
			}
			rr=true;
			lastr=x;
		}
		if(ch=='B'||ch=='P')
		{
			if(bb)
			{
				ans+=x-lastb;
				mb=max(mb,x-lastb);
			}
			bb=true;
			lastb=x;
		}
		if(ch=='P')
		{
			if(pp)ans+=min(0LL,x-lastp-mr-mb);
			lastp=x;mr=0;mb=0;pp=true;
		}
	}
	printf("%I64d\n",ans);
	return 0;
}


猜你喜欢

转载自blog.csdn.net/noone0/article/details/79918581