题目链接:
http://acm.bnu.edu.cn/v3/problem_show.php?pid=13319
一道典型的求解SG函数的题目,校内组队赛中遇到此题。开题时有比较清晰的解题思路,但是因为不常刷题导致写代码效率低下,一道题的代码写了近3h。最终因为一个没发现的小错误导致没能AC。实力还是太弱,还是需要努力。
先说说我错误的原因。大家知道求SG函数时,我们只需要把那些直接与终止态相连的状态作为递归终点,手算出它们的SG值即可(一般很容易算),剩下的状态的SG函数直接递归求解即可。以此题为例,我用一个结构体p{l,r,len}来表示一个长度为len,左侧方块为l,右侧方块为r的状态,l,r有三种状态0,1,2,分别代表没放标记、放‘X’和放'O'。这样,我们只需要手算出长度为1的状态{0,0,1}、{0,1,1}、{0,2,1}...的答案, 其他状态直接搜索求解即可,但我画蛇添足地手算了len=2时各个状态的SG函数。然后....就算错了....(让我一个人静一静...
所以说不要做一些画蛇添足的事,求SG函数还是让它它自己去算吧。
接下来说一下算过SG函数之后得到的规律:l==r&&r==0时,SG=(len&1)?1:0;l==0||r==0时,SG=len;剩下的情况中,若l==r,则SG=1否则SG=0。
代码:
#define sc scanf
#define pr printf
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define LL long long
using namespace std;
const int N = 200;
const LL mod = 1000000007;
struct p {
int l,r,len;
bool operator < (const p& b)const {
if(len==b.len&&l==b.l)
return r<b.r;
else if(len==b.len)
return l<b.l;
else return len<b.len;
}
};
char s[N];
p c[N];
map<p,int> mapp;
int dfs(p a) {
if(mapp.count(a))
return mapp[a];
if(a.len == 0)
return 0;
else if(a.len==1) {
if(a.l==0||a.r==0)
return 1;
else if(a.l==a.r)
return 1;
else
return 0;
} else {
int ans = 0;
bool vis[200];
memset(vis,0,sizeof(vis));
p p1,p2;
p1.l = a.l;
p1.r = 1;
p2.l = 1;
p2.r = a.r;
for(int i=0; i<a.len; ++i) {
if(a.l==1&&i==0)
continue;
if(a.r==1&&i==a.len-1)
continue;
p1.len = i;
p2.len = a.len-i-1;
vis[dfs(p1)^dfs(p2)] = 1;
}
p1.r = 2;
p2.l = 2;
for(int i=0; i<a.len; ++i) {
if(a.l==2&&i==0)
continue;
if(a.r==2&&i==a.len-1)
continue;
p1.len = i;
p2.len = a.len-i-1;
vis[dfs(p1)^dfs(p2)] = 1;
}
for(int i=0;; ++i)
if(!vis[i]) {
ans = i;
break;
}
mapp[a] = ans;
return mapp[a];
}
}
int main() {
//freopen("input.in","r",stdin);
int T;
int cas = 0;
sc("%d",&T);
while(T--) {
sc("%s",s);
int l = strlen(s);
int ct=0;
int tmp = 0;
c[0].l = 0;
int num = 0;
for(int i=0; i<l; ++i) {
if(s[i]=='X') {
c[tmp].r = 1;
c[tmp].len = ct;
c[++tmp].l = 1;
ct = 0;
num++;
} else if(s[i]=='O') {
c[tmp].r = 2;
c[tmp].len = ct;
c[++tmp].l = 2;
ct = 0;
num++;
}
if(s[i]!='.')
continue;
ct++;
}
c[tmp].r = 0;
c[tmp].len = ct;
c[++tmp].l = 0;
ct = 0;
int res =0;
for(int i=0; i<tmp; ++i)
res ^=dfs(c[i]);//打表找规律
pr("Case %d: ",++cas);
if(((num&1)&&res)||((!(num&1))&&(!res)))
puts("No");
else
puts("Yes");
}
return 0;
}