CF536D Tavas in Kansas

Tavas in Kansas

给定一张 𝑛 个点,𝑚 条边带边权的无向连通图 𝐺,每个点都有权值。𝐴, 𝐵 二人在 𝐺 上进行⼀个游戏。

开始时 𝐴 在 𝑠 点,𝐵 在 𝑡 点,他们需要轮流操作,每次操作者选择一个 𝑥,并获得所有离它距离不超过 𝑥 的点的权值。获得完某个点的权值之后,这个点的权值将变为 0 并打上标记。每次操作,必须获取至少一个未被标记过的点的权值。

两人轮流操作,都将使用最优策略, 𝐴 先手,请问是否最后 𝐴 获得的权值比 𝐵 多。

𝑛 ≤ 2000,𝑚 ≤ 105

题解

https://www.luogu.com.cn/blog/xht37/solution-cf536d

首先做两次 dijkstra 求出 \(\operatorname{dist}(s/t, 1\dots n)\) 并离散化,值域降为 \(\mathcal O(n)\)

由于 \(\mathcal O(n^2)\) 可以接受,因此直接 dp 即可。

\(f(P, S, T)\) 表示此时先手为 \(P\) ,还剩下 \(\operatorname{dist}(s, i) \ge S\)\(\operatorname{dist}(t, i) \ge T\) 的点 \(i\) 时,先手的最大得分。

则有

\(f(P, S, T) = \begin{cases} 0 & c(S, T) = 0 \\ \max_{c(A,T) < c(S,T)} s(S,T) - f(1,A,T) & P = 0 \\ \max_{c(S,B) < c(S,T)} s(S,T) - f(0,S,B) & P = 1 \end{cases}\)

要后缀 \(\min\) 优化,总时间复杂度 \(\mathcal O(n \log m + n^2)\)

实现上,可以递推出对于每个 \((S,T)\)\(\min_{i\ge S, j \ge T, c(i,j) < c(S,T)} i/j\) 的值,然后 \(f\) 值直接设为后缀 \(\min\)

CO int N=2e3+10;
CO int64 inf=1e18;
int n,m,a[N];
vector<pair<int,int> > to[N];
int64 ds[N],dt[N];

void spfa(int s,int64 dis[],int&cnt){
	static bool vis[N];
	fill(dis+1,dis+n+1,inf),fill(vis+1,vis+n+1,0);
	priority_queue<pair<int64,int>,vector<pair<int64,int> >,greater<pair<int64,int> > > q;
	q.push({dis[s]=0,s});
	while(q.size()){
		int x=q.top().second;q.pop();
		if(vis[x]) continue;
		vis[x]=1;
		for(CO pair<int,int>&e:to[x])
			if(dis[e.first]>dis[x]+e.second)
				q.push({dis[e.first]=dis[x]+e.second,e.first});
	}
	vector<int64> val(dis+1,dis+n+1);
	sort(val.begin(),val.end());
	val.erase(unique(val.begin(),val.end()),val.end());
	cnt=val.size();
	for(int i=1;i<=n;++i)
		dis[i]=lower_bound(val.begin(),val.end(),dis[i])-val.begin()+1;
}

int c[N][N],ns[N][N],nt[N][N];
int64 s[N][N],f[2][N][N];

int main(){
	read(n),read(m);
	int S=read<int>(),T=read<int>();
	for(int i=1;i<=n;++i) read(a[i]);
	for(int i=1;i<=m;++i){
		int x=read<int>(),y=read<int>(),w=read<int>();
		to[x].push_back({y,w}),to[y].push_back({x,w});
	}
	int cs; spfa(S,ds,cs);
	int ct; spfa(T,dt,ct);
	for(int i=1;i<=n;++i)
		++c[ds[i]][dt[i]],s[ds[i]][dt[i]]+=a[i];
	for(int i=cs;i>=1;--i)for(int j=ct;j>=1;--j){
		s[i][j]+=s[i+1][j]+s[i][j+1]-s[i+1][j+1];
		ns[i][j]=min(i==cs?cs:ns[i+1][j],j==ct?cs:ns[i][j+1]);
		nt[i][j]=min(i==cs?ct:nt[i+1][j],j==ct?ct:nt[i][j+1]);
		if(c[i][j]) ns[i][j]=i,nt[i][j]=j;
		f[0][i][j]=s[i][j]-f[1][ns[i][j]+1][j];
		f[1][i][j]=s[i][j]-f[0][i][nt[i][j]+1];
		if(i==1 and j==1) continue;
		f[0][i][j]=min(f[0][i][j],f[0][i][j+1]); // suffix min for f[1]
		f[1][i][j]=min(f[1][i][j],f[1][i+1][j]); // suffix min for f[0]
	}
	int64 ans=s[1][1]-2*f[0][1][1];
	if(ans<0) puts("Break a heart");
	else if(ans>0) puts("Cry");
	else puts("Flowers");
	return 0;
}

posted on 2020-04-22 15:01  autoint  阅读(144)  评论(0编辑  收藏  举报

导航