P9911 [COCI 2023/2024 #2] Kuglice

洛谷

由于两个人都会选择最优方案,因此可以考虑使用动态规划来模拟进行选择。

我们可以记录第一个人的得分,然后通过总得分减去第一人得分得到第二人得分。

首先我们考虑处理出每次取出什么位置会得到分数。

由于是从左右两边取出,因此可以得分的情况只能够是这一种球的最左端或者最右端。

我们可以先离散化再处理。

之后可以选择动态规划或者选择记忆化搜索。

我这边选择记忆化搜索,因为比较好思考。

记录左右两端取到哪里了,然后再记录是哪个人行动。

由于记录第一个人的值,因此第一个人行动时选择最优情况,并记录是否有得分,第二个人只需要求这次行动可以给第一个人造成最小收益即可。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,a[3005],L[3005],R[3005],dp[3005][3005],tmp[3005],cnt;
bool vis[3005][3005];
int dfs(int l,int r,bool f){
	if(l>r)return 0;
	if(vis[l][r])return dp[l][r];
	vis[l][r]=1;
	int &res=dp[l][r];
	if(f){
		res=0;
		if(l+1==L[a[l+1]]&&r>R[a[l+1]])res=max(res,dfs(l+1,r,0)+1);
		else res=max(res,dfs(l+1,r,0));
		if(r-1==R[a[r-1]]&&l<L[a[r-1]])res=max(res,dfs(l,r-1,0)+1);
		else res=max(res,dfs(l,r-1,0));
	}
	else {
		res=min(dfs(l+1,r,1),dfs(l,r-1,1));
	}
	return res;
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		tmp[++cnt]=a[i];
	}
	sort(tmp+1,tmp+cnt+1);
	cnt=unique(tmp+1,tmp+cnt+1)-tmp-1;
	for(int i=1;i<=n;i++){
		a[i]=lower_bound(tmp+1,tmp+cnt+1,a[i])-tmp;
		if(!L[a[i]])L[a[i]]=i;
		R[a[i]]=i;
	}
	int tmp=dfs(0,n+1,1);
	cout<<tmp<<':'<<cnt-tmp;
	return 0;
}
posted @ 2025-12-06 16:11  huhangqi  阅读(0)  评论(0)    收藏  举报
/*
*/