CF1728D Letter Picking 题解

CF1728D Letter Picking

思路:

区间 DP+博弈。

因为每次取完都放到第一个,所以最后一定是 Alice 赢或者平局。为什么呢?当最后只剩两个时,若两个不同,则 Alice 可以取较小的那个取胜,若相同,Alice 也会在前面的操作中选小的。而且 \(n\) 是偶数,所以不存在 Alice 取的字符串比 Bob 长的情况。

阅读题目和数据范围,我们猜测是区间 DP。设 \(f_{l,r}\) 表示剩余区间 \([l,r]\) 时,是平局还是 Alice 取胜。因为字典序按位比较,我们一次让双方都操作。
怎样判断这一次是平局?

  • Alice 取 \(s_l\)
    那么 Bob 只能选 \(s_{l+1}\)\(s_r\) 使得答案尽可能为平局。
    若 Bob 取 \(s_{l+1}\),那么只有 \(s_{l+1}\)\(s_l\) 相同,并且 \(f_{l+2,r}\) 为平局时答案为平局。
    若 Bob 取 \(s_{r}\),那么只有 \(s_{r}\)\(s_l\) 相同,并且 \(f_{l+1,r-1}\) 为平局时答案为平局。
    任一满足一种即可在 Alice 取 \(s_l\) 时平局。
  • Alice 取 \(s_r\)
    那么 Bob 只能选 \(s_{r-1}\)\(s_l\) 使得答案尽可能为平局。
    若 Bob 取 \(s_{r-1}\),那么只有 \(s_{r-1}\)\(s_r\) 相同,并且 \(f_{l,r-2}\) 为平局时答案为平局。
    若 Bob 取 \(s_{r}\),那么只有 \(s_{r}\)\(s_l\) 相同,并且 \(f_{l+1,r-1}\) 为平局时答案为平局。
    任一满足一种即可在 Alice 取 \(s_r\) 平局。

对于 Alice 的两种取法,Bob 都要有应对方法。所以这两种要都满足才能取得平局。
一点小优化:因为每次双方都操作,所以 \(f_{l,r}\) 只有在区间长度为偶数时有意义,那我们可以在枚举区间长度时只枚举偶数。

code:

#include<bits/stdc++.h>
using namespace std;
const int N=2002;
int T;
int f[N][N];//1表示Alice获胜,0表示平局。 
string s,t;
bool check(int l,int r){
	int p1,p2,p3,p4;
	p1=p2=p3=p4=0;
	if(s[l]==s[l+1]&&f[l+2][r]==0) p1=1;
	if(s[l]==s[r]&&f[l+1][r-1]==0) p2=1;
	if(s[r]==s[r-1]&&f[l][r-2]==0) p3=1;
	if(p1+p2>=1&&p2+p3>=1) return 1;//两种情况各至少满足一个
	return 0;
}
int main(){
	scanf("%d",&T);
	while(T--){
		cin>>s;
		int sl=s.size();	
		s='#'+s;
		for(int i=1;i<=sl;i++){
			for(int j=1;j<=sl;j++) f[i][j]=0;//初始化。 
		}
		for(int i=1;i<sl;i++) {
			if(s[i]==s[i+1]) f[i][i+1]=0;
			else f[i][i+1]=1; 
		}
		for(int len=4;len<=sl;len+=2){
			for(int l=1;l+len-1<=sl;l++){
				int r=l+len-1;
				if(check(l,r)) f[l][r]=0;
				else f[l][r]=1;
			}
		}
		if(f[1][sl]==1) printf("Alice\n");
		else printf("Draw\n");
		
	}
	return 0;
}
posted @ 2025-04-15 22:40  MoYujing  阅读(14)  评论(0)    收藏  举报