CF1728D

发布时间 2023-04-17 14:52:46作者: QAQ啥也不会

博弈论dp模板题

首先我们可以先确定dp状态 dp[round][L][R][0/1]表示第round轮,现在字符串为[L~R],上一轮的人取了左边还是右边

然后发现round是可以由字符串L~R确定而来的,因为每一轮只删除一个数,因此可以优化round这维

我们令dp[L][R][0/1]=1为 Alice 赢,dp[L][R][0/1]=0为平局,dp[L][R][0/1]=-1为Bob胜利

对于Alice是先手,所以我们只需要ans尽量大即可:

    if(round&1) //A的轮次
        ans=max(dfs(L+1,R,0),dfs(L,R-1,1));

对于Bob是后手,所以每次都要都还要考虑 Alice 选了啥:

其实也就四种情况:

1.Alice选了L-1,Bob选了L

2.Alice选了L-1,Bob选了R

3.Alice选了R+1,Bob选了L

4.Alice选了R+1,Bob选了R

 然后让ans尽可能小就行了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pb push_back   
#define popb pop_back  
#define fi first
#define se second
#define popcount __builtin_popcount
const int N=2010;
//const int M=;
const int inf=1e9;
//const ll INF=1e18;
int T,n,dp[N][N][2];
char s[N];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
int dfs(int L,int R,int op)
{
    int round=n-(R-L+1)+1;
    if(dp[L][R][op]!=inf) return dp[L][R][op];
    int ans;
    if(round&1) //A的轮次
        ans=max(dfs(L+1,R,0),dfs(L,R-1,1));
    else //B的轮次 
    {
        ans=inf;
        if(op==0) // A选了L-1的位置 
        {
            // B选了L的位置
            if(dfs(L+1,R,0)==1) ans=min(ans,1);
            else if(dfs(L+1,R,0)==-1) ans=min(ans,-1);
            else 
            {
                if(s[L-1]==s[L]) ans=min(ans,0);
                if(s[L-1]>s[L]) ans=min(ans,1);
                if(s[L-1]<s[L]) ans=min(ans,-1);
            }
            // B选了R的位置 
            if(dfs(L,R-1,1)==1) ans=min(ans,1);
            else if(dfs(L,R-1,1)==-1) ans=min(ans,-1);
            else 
            {
                if(s[L-1]==s[R]) ans=min(ans,0);
                if(s[L-1]>s[R]) ans=min(ans,1);
                if(s[L-1]<s[R]) ans=min(ans,-1);
            }
        }  
        else // A选了 R+1 的位置
        {
            // B选了L的位置
            if(dfs(L+1,R,0)==1) ans=min(ans,1);
            else if(dfs(L+1,R,0)==-1) ans=min(ans,-1);
            else 
            {
                if(s[R+1]==s[L]) ans=min(ans,0);
                if(s[R+1]>s[L]) ans=min(ans,1);
                if(s[R+1]<s[L]) ans=min(ans,-1);
            }
            // B选了R的位置 
            if(dfs(L,R-1,1)==1) ans=min(ans,1);
            else if(dfs(L,R-1,1)==-1) ans=min(ans,-1);
            else 
            {
                if(s[R+1]==s[R]) ans=min(ans,0);
                if(s[R+1]>s[R]) ans=min(ans,1);
                if(s[R+1]<s[R]) ans=min(ans,-1);
            }        
        }
    }    
    return dp[L][R][op]=ans;
} 
int main()
{
//    freopen("","r",stdin);
//    freopen("","w",stdout);
//    ios::sync_with_stdio(0);
//    cin.tie(0);
    T=read();
    while(T--)
    {
        scanf("%s",s+1);
        n=strlen(s+1);
        for(int i=1;i<=n;i++)
            for(int j=i;j<=n;j++)
                dp[i][j][0]=dp[i][j][1]=inf;
        int op=dfs(1,n,0);
        if(op==1) puts("Alice");
        else if(op==0) puts("Draw");
        else if(op==-1) puts("Bob");
    }
    return 0;
}