Division Game UVA - 11859 (Nim)题解


Division game is a 2-player game. In this game, there is a matrix of positive integers with N rows
and M columns. Players make their moves in turns. In each step, the current player selects a row.
If the row contains all 1s, the player looses. Otherwise, the player can select any number of integers
(but at least 1 and each of them should be greater than 1) from that row and then divides each of
the selected integers with any divisor other than 1. For example, 6 can be divided by 2, 3 and 6, but
cannot be divided by 1, 4 and 5. The player who first makes the matrix all 1s wins. In other words, if
in his/her move, player gets the matrix with all 1s, then he/she looses. Given the matrix, your task is
to determine whether the first player wins or not. Assume that both of the players will play perfectly
to win.
Input
The first line has a positive integer T, T ≤ 50, denoting the number of test cases. This is followed by
each test case per line.
Each test case starts with a line containing 2 integers N and M representing the number of rows
and columns respectively. Both N and M are between 1 and 50 inclusive. Each of the next N line each
contains M integers. All these integers are between 2 and 10000 inclusive.
Output
For each test case, the output contains a line in the format ‘Case #x: M’, where x is the case number
(starting from 1) and M is ‘YES’ when the first player has a winning strategy and ‘NO’ otherwise.
Sample Input
5
2 2
2 3
2 3
2 2
4 9
8 5
3 3
2 3 5
3 9 2
8 8 3
3 3
3 4 5
4 5 6
5 6 7
2 3
4 5 6
7 8 9
Sample Output
Case #1: NO
Case #2: NO
Case #3: NO
Case #4: YES
Case #5: YES


题目大意:玩家轮流选择某一行,将至少一个或者多个数变为他的真因数,两玩家都采取最佳策略,求游戏结果。
当每一行的所有数都是1的时候,就没有任何数可以变成真因数了,这时轮到谁谁就输了。任何一个合数都可以由几个质因数相乘得到,一个数变成他的真因数的过程,相当于除去他的一个或多个质因数,例如12的质因数为2,2,3,当他变成其真因数6时,相当于除去了质因数2,此时6还有三个真因数,6变成3时相当于除去质因数2,3只能除去质因数3变成1,这就很像nim游戏中的拿火柴的样子,对于一个数,你把他变成他的真因数的过程就相当于从他的质因数里取走一个或者多个,这题便转化成了n行,每行一个火柴堆,每个火柴堆的数量是该行所有数字的质因数数量之和,然后用nim求解。

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<vector>
#include<string>
#include<cmath>
#include<set>
#include<map>
#include<queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int mod = 1000000007;
const int maxm = 50000005;
const int maxn = 10005;
const int M = 25;
int n, m;
bool vis[maxn];
int line[55];
int zhi[maxn];
int tot;
void init(){
    tot = 0;
    for (int i = 2; i < maxn; i++){
        if (!vis[i]){
            zhi[tot++] = i;
            for (int j = i * 2; j < maxn; j += i){
                vis[j] = 1;
            }
        }
    }
}


int main() {
    init();
    int t,x;
    scanf("%d", &t);
    for(int cas=1;cas<=t;cas++){
        memset(line, 0, sizeof line);
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i++){
            for (int j = 0; j < m; j++){
                scanf("%d", &x);
                int cnt = 0;
                while (x!=1&&cnt<tot&&zhi[cnt]<=x){
                    if (x%zhi[cnt] == 0){ x /= zhi[cnt]; line[i]++; }
                    else{ cnt++; }
                }
            }
        }
        int ans = 0;
        for (int i = 0; i < n; i++){
            ans ^= line[i];
        }
        printf("Case #%d: ", cas);
        if (ans == 0){ printf("NO\n"); }
        else{ printf("YES\n"); }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值