Educational Codeforces Round 135 (Rated for Div. 2)D. Letter Picking(区间dp)

文章讲述了如何通过动态规划方法解决Alice和Bob之间的字母游戏问题,通过区间大小判断两人在给定字符串s中的输赢,最后输出胜者或平局的结果。

原题链接:D. Letter Picking
题目大意
Alice 和 Bob 在玩游戏。
给出一个长度为偶数的,非空的且仅含小写字母的字符串 s。每个玩家还拥有一个初始为空的字符串。
Alice 先手,两名玩家交替行动。在一次行动中,玩家可以取 s 首或尾字符,将其从s 中移除后加入到自己的字符串的最前面。
当 s 为空时游戏结束,拥有字典序更小的字符串的玩家获胜。若两名玩家的字符串相等则平局。
若 Alice 和 Bob 都足够聪明,判断谁会取胜,或者游戏为平局。
数据范围:1≤t≤1000,所有测试用例的字符串总长度不超过2000
解题思路
对于一个大区间的输赢,可以由小区间来判断。先从小区间考虑,加上两个字符后再作判断,由此拓展到n,考虑用区间dp来维护小区间的胜负
考虑令 Alice 赢为 0,平局为 1,Bob 赢为 2

1.建立dp数组

int dp[2005][2005]; //dp[i][j]表示区间i~j的输赢情况

2.初始化dp数组
从最小单元,即区间长度为2时开始初始化

for(int i=1;i<n;i++)dp[i][i+1]=(s[i]==s[i+1]);//当s[i]==s[i+1]时,双方平局,其他情况Alice获胜

3.状态转移
枚举每个区间的长度,分类讨论得到该区间的输赢情况

for(int len=4;len<=n;len+=2)
	{
		for(int l=1,r=len;r<=n;l++,r++)
		{
			ll=dp[l+2][r];//两人都从左边取
			lr=dp[l+1][r-1];//从两边各取一个
			rr=dp[l][r-2];//两人都从右边取
			//Alice获胜
			if(((ll==1&&s[l]<s[l+1])||ll==0)&&((lr==1&&s[l]<s[r])||lr==0))dp[l][r]=0;
			else if(((lr==1&&s[l]>s[r])||lr==0)&&((rr==1&&s[r]<s[r-1])||rr==0))dp[l][r]=0;
			//平局
			else if(((ll==1&&s[l]<=s[l+1])||ll==0)&&((lr==1&&s[l]<=s[r])||lr==0))dp[l][r]=1;
			else if(((lr==1&&s[r]<=s[l])||lr==0)&&((rr==1&&s[r]<=s[r-1])||rr==0))dp[l][r]=1;
			//其他情况Bob胜
			else dp[l][r]=2;
		}
	}

.得出结论
dp[1][n]为0 Alice 赢,为 1平局,为 2 Bob 赢

if(dp[1][n]==0)cout<<"Alice\n";
else if(dp[1][n]==1)cout<<"Draw\n";
else cout<<"Bob\n";

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
int dp[2005][2005]; 
void solve()
{
	memset(dp,0,sizeof(dp));
	string s;
	cin>>s;
	int n=s.size();
	s=" "+s;
	for(int i=1;i<n;i++)dp[i][i+1]=(s[i]==s[i+1]);//当s[i]==s[i+1]时,双方平局,其他情况Alice获胜
	int ll,lr,rr;
	for(int len=4;len<=n;len+=2)
	{
		for(int l=1,r=len;r<=n;l++,r++)
		{
			ll=dp[l+2][r];//两人都从左边取
			lr=dp[l+1][r-1];//从两边各取一个
			rr=dp[l][r-2];//两人都从右边取
			//Alice获胜
			if(((ll==1&&s[l]<s[l+1])||ll==0)&&((lr==1&&s[l]<s[r])||lr==0))dp[l][r]=0;
			else if(((lr==1&&s[l]>s[r])||lr==0)&&((rr==1&&s[r]<s[r-1])||rr==0))dp[l][r]=0;
			//平局
			else if(((ll==1&&s[l]<=s[l+1])||ll==0)&&((lr==1&&s[l]<=s[r])||lr==0))dp[l][r]=1;
			else if(((lr==1&&s[r]<=s[l])||lr==0)&&((rr==1&&s[r]<=s[r-1])||rr==0))dp[l][r]=1;
			//其他情况Bob胜
			else dp[l][r]=2;
		}
	}
	if(!dp[1][n])cout<<"Alice\n";
	else if(dp[1][n]==1)cout<<"Draw\n";
	else cout<<"Bob\n";
}
signed main(){
	int t=1;
	cin>>t;
	while(t--)solve();
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值