LightOJ 1229 Treblecross(SG函数打表 + 遍历)题解

题意:给你一串含“.”和“X”的字串,每次一个玩家可以把‘."变成“X”,谁先弄到三个XXX就赢。假如先手必赢,输出所有能必赢的第一步,否则输出0。

思路:显然如果一个X周围两格有X那么肯定能一步变成XXX,所以两个人都要避免在自己回合产生这种情况。如果一开始就存在上述情况,那么肯定是那一步。否则我遍历每一个空格看看能不能下这一步。满足我在这个空格变成“X”不会造成上述情况,然后算出nim和是否留给对手一个必败态。

设sg[x]表示长度为x的空格的sg函数,然后我遍历1~x位置变成“X”,那么空格键会被我分成两块(比如.....我在3位置下X,那么空格被我分成了左0右0两块,注意X旁边两块不能动)。

代码:

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
const int maxn = 200 + 10;
const int seed = 131;
const ll MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
int sg[maxn], s[maxn], ans[maxn], pos;
char str[maxn];
void getSG(){
    sg[0] = 0;
    for(int i = 1; i < maxn; i++){
        memset(s, 0, sizeof(s));
        for(int j = 1; j <= i; j++){
            int t = 0;
            if(i - j - 2 >= 0) t ^= sg[i - j - 2];
            if(j - 3 >= 0) t ^= sg[j - 3];
            s[t] = 1;
        }
        for(int j = 0; j < maxn; j++){
            if(!s[j]){
                sg[i] = j;
                break;
            }
        }
    }
}
bool check(){
    ll ret = 0;
    int num = 0, len = strlen(str);
    for(int i = 0; i < len; i++){
        if(str[i] == 'X'){
            if((i >= 1 && str[i - 1] == 'X') || (i >= 2 && str[i - 2] == 'X') || (i + 1 < len && str[i + 1] == 'X') || (i + 2 < len && str[i + 2] == 'X')){
                return false;
            }
            if(str[i - num - 1] == 'X' && i - num - 1 >= 0)
                num -= 2;
            num -= 2;
            if(num >= 0) ret ^= sg[num];
            num = 0;
        }
        else{
            num++;
        }
    }
    if(str[len - 1 - num] == 'X' && len - 1 - num >= 0)
            num -= 2;
    if(num >= 0) ret ^= sg[num];
    return ret == 0;
}
void solve(){
    pos = 0;
    int len = strlen(str);
    for(int i = 0; i < len; i++){
        if(str[i] == '.'){
            str[i] = 'X';
            if(i + 1 < len && i - 1 >= 0 && str[i + 1] == 'X' && str[i - 1] == 'X'){
                ans[pos++] = i + 1;
            }
            else if(i + 1 < len && i + 2 < len && str[i + 1] == 'X' && str[i + 2] == 'X'){
                ans[pos++] = i + 1;
            }
            else if(i - 2 >= 0 && i - 1 >= 0 && str[i - 2] == 'X' && str[i - 1] == 'X'){
                ans[pos++] = i + 1;
            }
            else if(check()){
                ans[pos++] = i + 1;
            }
            str[i] = '.';
        }
    }
}
int main(){
    int T, Case = 1;
    getSG();
    scanf("%d", &T);
    while(T--){
        scanf("%s", str);
        solve();
        printf("Case %d:", Case++);
        if(pos == 0) printf(" 0\n");
        else{
            for(int i = 0; i < pos; i++){
                printf(" %d", ans[i]);
            }
            printf("\n");
        }
    }
    return 0;
}

 

posted @ 2018-09-27 22:44  KirinSB  阅读(295)  评论(0编辑  收藏  举报