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

D. Letter Picking

题目大意

给一个字符串s,长度为偶数,Alice和Bob初始时都只有一个空字符串,Alice先行动。每次从s的头和尾选择一个字符,插入自己的字符串的首。

到最后,谁的字符串的字典序小谁赢。

分析

看到数据范围,不免让人想到DP。因为每次操作,选择都是头和尾操作,因此我们考虑区间DP。

初始化是对于长度为2,我们只需要看两个字符相同与否,相同则平局,否则则A赢。

接下来,开始进行区间DP,每次我们只需要考虑偶数长度,接下来的分析会知道为什么。

dp[l][r]:1表示为A赢,0表示平局,-1表示B赢

我们考虑,每次都是A先行动,然后B行动,依据此可以分为四种转移,

A选l

对于A选l后,B选择有两种情况,其一定选择能使答案变小的选择。设在A选l的条件下,B两种选择结果最小为ret1,初始化为1

B选r

if(dp[l+1][r-1]) ret1 = min(ret1,dp[l+1][r-1]);
else if(s[r]<s[l]) ret1 = -1;
else if(s[r]==s[l]) ret1 = min(ret1,0);

B选l+1

if(dp[l+2][r]) ret1 = min(ret1,dp[l+2][r]);
else if(s[l+1]<s[l]) ret1 = -1;
else if(s[l+1]==s[l]) ret1 = min(ret1,0);

A选r

此时,我们在设一个ret2,与ret1定义相同。

B选l

if(dp[l+1][r-1]) ret2 = min(ret2,dp[l+1][r-1]);
else if(s[r]>s[l]) ret2 = -1;
else if(s[r]==s[l]) ret2 = min(ret2,0);

B选r-1

if(dp[l][r-2]) ret2 = min(ret2,dp[l][r-2]);
else if(s[r-1]<s[r])  ret2 = -1;
else if(s[r-1]==s[r]) ret2 = min(ret2,0);

对于A的两种选择,A一定是选择能让答案尽量大的结果,因此,dp[l][r] = max(ret1,ret2)

来看代码吧

Ac_code

#include <bits/stdc++.h>
#define fi first    
#define se second    
#define endl '\n'
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
typedef long long LL;
using namespace std;
const int N = 2010,M = N*2;

int dp[N][N];
string s;
int n;

void solve() 
{
    cin>>s;
    n = s.size();
    s = " " + s;
    for(int i=1;i<=n-1;i++)
        if(s[i]==s[i+1]) dp[i][i+1] = 0;
        else dp[i][i+1] = 1;
    for(int len=4;len<=n;len+=2)
        for(int l=1;l<=n-len+1;l++)
        {
            int r = l + len - 1;
            dp[l][r] = -1;
            int ret = 1;
            if(dp[l+1][r-1]) ret = min(ret,dp[l+1][r-1]);
            else if(s[r]<s[l]) ret = -1;
            else if(s[r]==s[l]) ret = min(ret,0);
            if(dp[l+2][r]) ret = min(ret,dp[l+2][r]);
            else if(s[l+1]<s[l]) ret = -1;
            else if(s[l+1]==s[l]) ret = min(ret,0);
            dp[l][r] = max(dp[l][r],ret);
            ret = 1;
            if(dp[l+1][r-1]) ret = min(ret,dp[l+1][r-1]);
            else if(s[r]>s[l]) ret = -1;
            else if(s[r]==s[l]) ret = min(ret,0);
            if(dp[l][r-2]) ret = min(ret,dp[l][r-2]);
            else if(s[r-1]<s[r])  ret = -1;
            else if(s[r-1]==s[r]) ret = min(ret,0);
            dp[l][r] = max(dp[l][r],ret);
        }
    if(dp[1][n]==1) cout<<"Alice\n";
    else if(dp[1][n]==0) cout<<"Draw\n";
    else cout<<"Bob\n";
}
 
int main() 
{
    ios;
    int T=1;
    cin>>T;
 
    while(T -- ) {
        solve();
    }
 
    return 0;
}
posted @ 2022-09-09 17:24  艾特玖  阅读(172)  评论(0)    收藏  举报