Codeforces 335C More Reclamation 博弈

题目大意:

就是现在有一条宽度是2的河流, 已经有一部分被占用为陆地了, 现在两座城市轮流来占用河流的一部分土地, 一条河不能被封堵住(第a行第1列和第a + 1行第2列被封住也算封死), 在这个前提下双方轮流选择, 直到一方不能选择为止, 最后下手选择的人赢, 也就是轮到谁而那个城市没有选择余地的时候那个城市输


大致思路:

首先可以将连续的没有被占用过的行作为一段来考虑, 那么这样的一段有4种情况

1. 上下是边界, 也就是这是一整条河流

2. 上下边界中有一个是边界, 另一边有1格被占用

3. 上下都有一格被占用, 且上下被占用的格子在同一列

4. 上下都有一格被占用且上下被占用的格子不在同一列

对于长度为L的且相邻的边界满足以上4种类型的求出其SG值即可

最后将题目输入的河流按照连续的未占用进行分割, 成为多个游戏的和

求出游戏的和判断是否SG = 0即可


代码如下:

Result  :  Accepted     Memory  :  8 KB     Time  :  30 ms

/*
 * Author: Gatevin
 * Created Time:  2015/3/5 10:27:43
 * File Name: Kotori_Itsuka.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

/*
 * There are four types of segments
 * 1. The entire river
 * 2. A section of river containing one of the ends
 * 3. A section of river blocked at both at ends in the same column
 * 4. A section of river blocked at both ends in different columns
 */

/*
 * 就是对每一个长度为L*2的没有被填充一段根据其上下的column被占用情况分类成以上4类就好
 * 然后对于这样的转移求出所有的SG[i][j]
 */
int SG[110][5];//用SG[i][j]表示长度为i类型为j的一段的SG值
map<int, bool> vis;
//其中SG[0][j] = 0
//注意SG[0][4]其实是不可取的, 因为河道被封死了

struct Die
{
    int r, c;
    Die(){}
};
Die die[110];

bool cmp(Die d1, Die d2)
{
    return d1.r < d2.r;
}

int main()
{
    for(int i = 1; i <= 100; i++)
    {
        vis.clear();
        for(int j = 0; j < i; j++)
            vis[SG[j][2]^SG[i - j - 1][2]] = 1;
        SG[i][1] = 0;
        while(vis[SG[i][1]]) SG[i][1]++;
        
        vis.clear();
        for(int j = 0; j < i; j++)
            vis[SG[j][3]^SG[i - j - 1][2]] = 1;
        for(int j = 1; j < i; j++)//j从1开始因为SG[0][4]不可取, 以下同理
            vis[SG[j][4]^SG[i - j - 1][2]] = 1;
        SG[i][2] = 0;
        while(vis[SG[i][2]]) SG[i][2]++;
        
        vis.clear();
        for(int j = 0; j < i; j++)
            vis[SG[j][3]^SG[i - j - 1][3]] = 1;
        for(int j = 1; j < i - 1; j++)
            vis[SG[j][4]^SG[i - j - 1][4]] = 1;
        SG[i][3] = 0;
        while(vis[SG[i][3]]) SG[i][3]++;
        
        vis.clear();
        for(int j = 0; j < i - 1; j++)
            vis[SG[j][3]^SG[i - j - 1][4]] = 1;
        for(int j = 1; j < i; j++)
            vis[SG[j][4]^SG[i - j - 1][3]] = 1;
        SG[i][4] = 0;
        while(vis[SG[i][4]]) SG[i][4]++;
    }
    int row, n;
    scanf("%d %d", &row, &n);
    if(n == 0)
    {
        if(SG[row][1]) printf("WIN\n");
        else printf("LOSE\n");
        return 0;
    }
    for(int i = 1; i <= n; i++)
        scanf("%d %d", &die[i].r, &die[i].c);
    sort(die + 1, die + n + 1, cmp);
    int sg = 0;
    sg ^= SG[die[1].r - 1][2];//对于很多段段求游戏的和
    for(int i = 1; i < n; i++)
    {
        if(die[i].c == die[i + 1].c) sg ^= SG[die[i + 1].r - die[i].r - 1][3];
        else sg ^= SG[die[i + 1].r - die[i].r - 1][4];
    }
    sg ^= SG[row - die[n].r][2];
    if(sg) printf("WIN\n");
    else printf("LOSE\n");
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值