【codeforces 787C】Berzerk

【题目链接】:http://codeforces.com/contest/787/problem/C

【题意】

给你怪物一开始所在的位置;
然后两人轮流操作;
可以选择让这个怪物前进自己的集合里面所拥有的数字所代表的步数;
对于2..n这些怪物的起点以及谁先进行游戏这些信息;
让这个怪物到位置1的人赢
判断谁能赢,输,或者游戏一直循环下去

【题解】

设f[i][j]表示i先玩,然后怪物一开始的位置为j的结果;

//-2表示输,-1表示赢,0表示不确定
f[1][1]=f[2][1]=-2;
即如果谁面临了怪物到达了1这个位置这个状态,他就输了;
因为这表示对方已经完成游戏了;
这样就代表先手输了;
然后对于这些为-2的状态;
可以往前推前一个人的状态;

前一个人,他走一步(通过自己集合里面的步数)到达了-2的状态;
也就是说让对方面临了先手输的状态,本来你是先手,然后你走一步,对方就变成先手啦,那么对方面临了先手输的状态,那么你就赢了;
因此对于所有能够走到-2的状态;
置其状态为先手赢;
然后再去找那些;
无论用集合里面哪个元素走,都会让对方面临先手赢状态的状态;
这些状态,置它们为先手输;
因为它们无论怎么走,对方都能面对先手赢的状态;
然后对于其他的状态,都是不确定.
写个倒推就好;
具体看代码

【完整代码】

#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%lld",&x)
#define ref(x) scanf("%lf",&x)

typedef pair<int,int> pii;
typedef pair<LL,LL> pll;

const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
const double pi = acos(-1.0);
const int N = 7e3+100;

int k[3],n;
int s[3][N];
int g[3][N];
queue <pii> dl;

void in()
{
    rei(n);
    rep1(i,1,2)
    {
        rei(k[i]);
        rep1(j,1,k[i])
            rei(s[i][j]);
    }
}

void get_ans()
{
    dl.push(mp(1,1)),dl.push(mp(2,1));
    g[1][1] = -2,g[2][1] = -2;
    while (!dl.empty())
    {
        int f = dl.front().fi,x = dl.front().se;
        int nex = 3-f;
        dl.pop();
        rep1(i,1,k[nex])
        {
            int y = x-s[nex][i];
            if (y<=0)
                y+=n;
            if (g[f][x]==-2)
            {
                if (g[nex][y]!=-1)
                {
                    g[nex][y] = -1;
                    dl.push(mp(nex,y));
                }
            }
            else
            {//g[f][x] = -1
                if (g[nex][y]<0) continue;//如果已经确定了,就不用计数了
                g[nex][y]++;//用来记录这个状态用集合里面的元素走一步会遇到多少个先手赢的状态,这里是直接在这个数组上计数,一数组两用
                if (g[nex][y]==k[nex])//如果全都是先手赢,那么这个状态就是先手输
                {
                    g[nex][y] = -2;
                    dl.push(mp(nex,y));
                }
            }
        }
    }
}

void o()
{
    rep1(i,2,n)
        {
            if (g[1][i]==-2)
                printf("Lose");
            else
                if (g[1][i]==-1)
                    printf("Win");
            else
                printf("Loop");
            if (i==n)
                puts("");
            else
                putchar(' ');
        }
    rep1(i,2,n)
        {
            if (g[2][i]==-2)
                printf("Lose");
            else
                if (g[2][i]==-1)
                    printf("Win");
            else
                printf("Loop");
            if (i==n)
                puts("");
            else
                putchar(' ');
        }
}

int main()
{
    //freopen("F:\\rush.txt","r",stdin);
    in();
    get_ans();
    o();
    //printf("\n%.2lf sec \n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}
posted @ 2017-10-04 18:45  AWCXV  阅读(540)  评论(0编辑  收藏  举报