题解:P9911 [COCI 2023/2024 #2] Kuglice

[COCI 2023/2024 #2] Kuglice题解

题面

题目描述

一个双端队列里面有 n 个球,每个球有一个颜色。A 和 B 玩一个游戏:

A 先手,两个人轮流操作,每次从队列的最左端或者最右端拿出一个球,如果这种颜色的球是第一次被拿出,拿出它的人获得 1 分。所有球都拿完后游戏结束。

假设 A 和 B 都以最优策略操作,请求出最终得分是多少。

输入格式

第一行一个整数 n。

第二行 n 个整数 a1∼an​ 表示从左到右每个球的颜色。

输出格式

输出一行两个以 : 隔开的整数(形如 a:b),a 表示 A 最终的得分,b 表示 B 最终的得分。

输入输出样例

输入 #1

5
1 1 2 1 1

输出 #1

1:1

输入 #2

6
1 2 3 1 2 3

输出 #2

2:1

说明/提示

数据范围

Subtask分值特殊性质
117ai​≤2
210n≤20
326ai​≤20
415n≤300
542

对于所有数据,1≤n≤3000,1≤ai​≤n。

题目大意

很好理解,就是问两个人拿球,谁先拿某种颜色谁加分,求分数。

题目思路

我们可以用区间DP解题。 先设一个数组f[i][j]表示取完区间[i,j]内的球,先手比后手多出来的分数。

再设shu表示总共能得到的分数,那么根据小学知识,先手能得到的总分就是(shu+f[1][n])/2,后手能得到的总分就是shu-(shu+f[1][n])/2。

然后,再设两个数组shou[i]和wei[i],表示i元素出现的最早和最晚位置,因为取i元素只能在这两个位置取。

接下来来看状态转移方程。因为只能在左右两端取球,所以f[i][j]的状态转移只能跟f[i+1][j]和f[i][j-1]有关。

并且,之前说过取i元素只能在这最早和最晚位置取,所以,只要满足shou[a[i]]>=i&&wei[a[i]]<=j,第i个球的颜色就一定只在区间内出现过。

假设先手取走了i号球,那么对于区间[i+1,j],先手就变成了原来的后手,所以应该用取走i号球的得分减去f[i+1][j]。

先手取走了j号球也同理:对于区间[i,j-1],先手也变成了原来的后手,所以应该用取走j号球的得分减去f[i][j-1]。

这样,我们就得到了如下状态转移方程:

f[i][j]=max(cc(i,j,a[i])-f[i+1][j],cc(i,j,a[j])-f[i][j-1]);

其中,cc(i,j,k)表示计算在[i,j]内取走颜色为k的球的得分。

代码见下

#include<bits/stdc++.h>
using namespace std;
long long n,m,a[1000010],shu,shou[1000010],wei[1000010],f[3010][3010];
bool cu[1000010];
bool cc(int i,int j,int k){
    if(shou[k]>=i&&wei[k]<=j) return 1;
    else return 0;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(cu[a[i]]==0){
			cu[a[i]]=1;
			shu++;
			shou[a[i]]=i;
		}
		wei[a[i]]=i;
	} 
	for(int l=1;l<=n;l++){
		for(int i=1;i<=n;i++){
			int j=l+i-1;
			f[i][j]=max(cc(i,j,a[i])-f[i+1][j],cc(i,j,a[j])-f[i][j-1]);
		}
	}
	cout<<(shu+f[1][n])/2<<":"<<shu-(shu+f[1][n])/2;
	return 0;
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值