原题链接: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;
}
文章讲述了如何通过动态规划方法解决Alice和Bob之间的字母游戏问题,通过区间大小判断两人在给定字符串s中的输赢,最后输出胜者或平局的结果。
546






