P3686 [CERC2016] 爵士之旅 Jazz Journey - 贪心


题解

可以发现,对于巡演的路线 \(x\to y\)\(a\to b\),若 \(\min(x,y)\neq \min(a,b)\)\(\max(x,y)\neq \max(a,b)\),则其答案互不影响。不妨设 \(x,我们需要对每一种 \((x,y),(y,x)\) 求出最小值。

将巡演路线中 \(x\to y\) 记作 \((\)\(y\to x\) 记作 \()\),则它形成了一个仅由左右括号组成的序列。设 \(A\)\(x\to y\) 的最优价钱,\(B\) 同理;\(AB\)\(x\to y\to x\) 的最优价钱,\(BA\) 同理。则有:\(A=\min(\operatorname{cost}(x\to y),AB),AB=\min(A+B,\operatorname{cost}(x\to y\to x))\)\(B,BA\) 同理。

不妨设 \(AB,于是,最优策略是:不断地删去括号序列中的 \(()\) 子序列(不必连续),然后不断地删去 \()(\) 子序列,直到只剩下若干 \((\)\()\)

\(AB>BA\),则只需要将所有左、右括号调换,然后 \(A,B\) 调换,\(AB,BA\) 调换,再执行上面的策略即可。

注意 \(\max(AB,BA)\) 可能会达到 \(2\times 10^9\),因此 \(\inf\) 要开得大一点。

代码
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
template void Read(T &_x){
	_x=0;int _f=1;
	char ch=getchar();
	while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();
	while(isdigit(ch)) _x=_x*10+(ch^48),ch=getchar();
	_x*=_f;
}
template void Read(T &_x,Args& ...others){
	Read(_x);Read(others...);
}
typedef long long ll;
typedef pair pii;
const ll Inf=0x3f3f3f3f3fLL;
const int N=3e5+5;
int n,d,m;
map mp;
void Insert(int x,int y){
	if(x one,two;
void Insert2(map &fli,int u,int v,int p){
	pii x(u,v);
	if(!fli.count(x)) fli.insert({x,p});
	else fli[x]=min(fli[x],ll(p));
}
ll Find(const map &fli,int u,int v){
	pii x(u,v);
	if(!fli.count(x)) return Inf;
	return fli.at(x);
}
int rem[N];
ll Calc(const string &s,ll cost,char c){
	ll res=0;
	stack stk;
	for(int i=0;i1) Insert(pre,x);
		pre=x;
	}
	Read(m);
	For(i,1,m){
		int u,v,p;char temp[5];
		Read(u,v);scanf("%s",temp);Read(p);
		if(temp[0]=='O') Insert2(one,u,v,p);
		else Insert2(two,u,v,p);
	}
	ll ans=0;
	for(const auto &pr:mp){
		int x=pr.first.first,y=pr.first.second;
		string s=pr.second;
		for(int i=0;i