2021牛客暑期多校训练营1A-Alice and Bob

题目链接

题意:Alice和Bob有两堆石子,每次可以从某一堆中取出k颗石子,在另一堆取出s*k(s>=0)颗石子,拿走场上最后一颗石子的人胜利

碎碎念念:一开始想找规律,但没找到,后来想到sg,但二维sg显然超时,最后没做出这题,还是思维太僵硬了,这题不用进行异或操作,只需要知道sg的值是否为0,所以并不用sg定理之类的东西

解析(表达的不是很好,需要自己想一想):
用x表示第一堆石子数,y表示第二堆石子数,加入(x,y)是一个必败状态,那么可以取走石子一次直接形成(x,y)的状态(x1,y1)必然不是必败状态,如果(x,y)不是必败点,那么可以取走石子一次直接形成(x,y)的状态(x1,y1)不能确定其胜败情况,综上,我们只需要关注一个点能不能由必败点得到,即是否有x=x1+k,y=y1+sk或者x=x1+sk,y=y1+k,如果可以,则该点不是必败点,如果一个点所有的必败点都无法得到,那么这个点也是必败点。
现在存在一个问题,我们怎么得到初始的必败点,我们上述都是由取石子后推向取石子前,自然可以想到能不能以(0,0)作为原初点,现在简单论述一下正确性,显然能由(0,0)直接得到的点(k,sk)/(sk,k)不是必败点,有推导式子x=x1+k,y=y1+s*k可以知道,一个必败点从任意必败点(石子数量小的)都无法用推导式得到,当我们推导时遇到第一个不能到达的点时此点必为必败点,因为此状态无法直接取完,但取走一部分后是可以一次直接取走的,剩下的必败点同理

AcCode
tip:时间卡的比较紧,可以由此方法得到所有必败点后打表

// #pragma GCC diagnostic error "-std=c++11"
// #pragma GCC optimize("-fdelete-null-pointer-checks,inline-functions-called-once,-funsafe-loop-optimizations,-fexpensive-optimizations,-foptimize-sibling-calls,-ftree-switch-conversion,-finline-small-functions,inline-small-functions,-frerun-cse-after-loop,-fhoist-adjacent-loads,-findirect-inlining,-freorder-functions,no-stack-protector,-fpartial-inlining,-fsched-interblock,-fcse-follow-jumps,-fcse-skip-blocks,-falign-functions,-fstrict-overflow,-fstrict-aliasing,-fschedule-insns2,-ftree-tail-merge,inline-functions,-fschedule-insns,-freorder-blocks,-fwhole-program,-funroll-loops,-fthread-jumps,-fcrossjumping,-fcaller-saves,-fdevirtualize,-falign-labels,-falign-loops,-falign-jumps,unroll-loops,-fsched-spec,-ffast-math,Ofast,inline,-fgcse,-fgcse-lm,-fipa-sra,-ftree-pre,-ftree-vrp,-fpeephole2",3)
// #pragma GCC target("avx","sse2")
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn = 5005;

int n, m;
bool sg[maxn][maxn];

inline void getSg(int x, int y) {
    for (int upx = 1; ; upx++) {
        if (upx + x > 5000 && upx + y > 5000)return;
        for (int upy = 0;; upy++) {
            int up = upx * upy;
            if (up + y > 5000 && up + x > 5000)break;
            if (up + y <= 5000 && upx + x <= 5000) {
                sg[x + upx][y + up] = 1;
                sg[y + up][x + upx] = 1;
            }
            if (y + upx <= 5000 && x + up <= 5000) {
                sg[y + upx][x + up] = 1;
                sg[x + up][y + upx] = 1;
            }
        }
    }
}

int main() {
    for (int i = 0; i <= 5000; i++) {
        for (int j = 0; j <= i; j++) {
            if (!sg[i][j]) getSg(i, j);
            //if (!sg[i][j] && i < j) cout << "sg==0 " << i << " " << j << endl;
        }
    }
    int t;
    scanf("%d", &t);
    while (t--) {
        int n, m;
        scanf("%d %d", &n, &m);
        //if (m > n) swap(n, m);
        if (n < 2 || m < 2) {
            printf("Alice\n");
        }
        else if (sg[n][m]) {
            printf("Alice\n");
        }
        else {
            printf("Bob\n");
        }
    }
}
上一篇:upx 尺寸单位换算


下一篇:发布QT生成的程序,用Enigma.Virtual.Box打包成单文件,以及与UPX的冲突