Codeforces 168D Wizards and Huge Prize

本文详细解析 CodeForces 168D 题目,通过将游戏区域分解为独立小块并运用 SG 函数求解游戏策略,特别讨论了如何处理斜向切割带来的挑战,采用黑白染色方法实现有效分割。

传送门:http://codeforces.com/problemset/problem/168/d

思路:这题比较恶心,细节很多,不过还好cf可以看数据...

首先考虑一个弱化版,只会横着或竖着以及横着和竖着一起来。

我们可以发现,一次操作后就相当于把一个大的游戏分成1或2或4个独立小游戏

SG值与位置也有关系,所以SG[u][d][l][r]表示左上坐标为(u,d)右下坐标为(l,r)的SG值

然后对于斜着的,我们考虑把它旋转45度,但是这有一个问题,一次操作并不能分出几个独立的小游戏(画图就可以发现了)

于是考虑把棋盘黑白染色,这样就可以分出独立的游戏了。


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int sg[25][25][25][25],b[25][25],n,N,M;char a[25][25];bool bo[1010];

int work(int u,int d,int l,int r){
	if (u>d||l>r) return 0;
	if (sg[u][d][l][r]!=-1) return sg[u][d][l][r];	
	for (int i=u;i<=d;i++)
		for (int j=l;j<=r;j++)
			if (b[i][j]==1) work(u,i-1,l,r),work(i+1,d,l,r);
			else if (b[i][j]==2) work(u,d,l,j-1),work(u,d,j+1,r);
			else if (b[i][j]==3) work(u,i-1,l,j-1),work(u,i-1,j+1,r),work(i+1,d,l,j-1),work(i+1,d,j+1,r);
	memset(bo,0,sizeof(bo));
	for (int i=u;i<=d;i++)
		for (int j=l;j<=r;j++)
			if (b[i][j]==1) bo[work(u,i-1,l,r)^work(i+1,d,l,r)]=1;
			else if (b[i][j]==2) bo[work(u,d,l,j-1)^work(u,d,j+1,r)]=1;
			else if (b[i][j]==3) bo[work(u,i-1,l,j-1)^work(u,i-1,j+1,r)^work(i+1,d,l,j-1)^work(i+1,d,j+1,r)]=1;
	for (int i=0;;i++) if (!bo[i]) return sg[u][d][l][r]=i;
}

int getans(int odd){
	memset(sg,-1,sizeof(sg));
	memset(b,0,sizeof(b));
	for (int i=1;i<=N;i++)
		for (int j=1;j<=M;j++)
			if (((i+j)&1)==odd)
				b[(i+j)>>1][(j-i+N+1)>>1]=a[i][j]=='L'?1:a[i][j]=='R'?2:3;
	/*for (int i=1;i<=n;i++,puts(""))
		for (int j=1;j<=n;j++)
			printf("%c",b[i][j]==1?'L':b[i][j]==2?'R':b[i][j]==3?'X':'0');
	puts("");*/ 
	return work(1,n,1,n);
}

int main(){
	while (scanf("%d%d",&N,&M)!=EOF){
		n=(N+M)>>1;
		for (int i=1;i<=N;i++) scanf("%s",a[i]+1);
		puts(getans(0)^getans(1)?"WIN":"LOSE");
	}
	return 0;
}


虽然给定引用中未直接提及“Kuroni and Simple Strings”题目的详细信息,但通常这类题目可能与字符串处理、括号匹配等相关。一般而言,题目可能会给出一个由括号组成的字符串,要求找出能移除的最大数量的不相交的合法括号对,并输出移除这些括号对后的相关信息。 ### 解法分析 #### 栈解法 栈解法是处理括号匹配问题的经典方法。通过遍历字符串,将左括号压入栈中,遇到右括号时,若栈顶为左括号,则将栈顶元素弹出,表示这是一对匹配的括号。 ```python s = input() stack = [] pairs = [] for i, char in enumerate(s): if char == '(': stack.append(i) else: if stack: left_index = stack.pop() pairs.append((left_index + 1, i + 1)) if not pairs: print(0) else: print(1) print(len(pairs) * 2) result = [] for l, r in pairs: result.extend([l, r]) result.sort() print(" ".join(map(str, result))) ``` #### 双指针解法 双指针解法从字符串的两端向中间遍历,分别使用两个指针 `left` 和 `right`。`left` 指针从左向右寻找 `(`,`right` 指针从右向左寻找 `)`,当找到一对匹配的括号时,将它们标记为已移除,继续寻找下一对匹配的括号,直到无法再找到匹配的括号为止。 ```python s = input() n = len(s) left = 0 right = n - 1 pairs = [] while left < right: while left < right and s[left] != '(': left += 1 while left < right and s[right] != ')': right -= 1 if left < right: pairs.append((left + 1, right + 1)) left += 1 right -= 1 if not pairs: print(0) else: print(1) print(len(pairs) * 2) result = [] for l, r in pairs: result.extend([l, r]) result.sort() print(" ".join(map(str, result))) ``` ### 复杂度分析 - **栈解法**:时间复杂度为 $O(n)$,其中 $n$ 是字符串的长度。空间复杂度为 $O(n)$,主要用于栈的空间开销。 - **双指针解法**:时间复杂度为 $O(n)$,空间复杂度为 $O(n)$,主要用于存储匹配的括号对。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值