题目传送门:http://codeforces.com/problemset/problem/850/C
博弈题,题目大意是给你一些数字,可以有这样的操作,选一个质数
p
和一个正整数
先考虑所有数字都是2的倍数的情况,可以很显然的发现如果只有两个2,这样仍然是先手必胜,显然这样并不是一个nim游戏,因为可以一下子“把两堆石子取走”,故而同时有多个 2k 和只有一个 2k 的情况是相同的。而且一个2和一个4的情况下,我们也不能简单的将只有一个2的情况和只有一个4的情况下的sg值异或起来,结果显然不对。因为我们取 2k 时,对所有 m>=k , 2m 都会变成 2m−k ,而小于的情况下数字并不改变。
由上面的性质我们很容易想到位运算,第
i
位表示
考虑任意情况,显然我们可以分解质因数,存下来分解后每个质数及其指数的情况,和只有2的情况是一样的,这回我们可以看作是一个nim游戏了,将每个质数的sg异或起来就是答案。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <set>
using namespace std;
const int MAX = 1e5 + 10;
int prime[MAX], vis[MAX], cnt;
map<int, int> m, sg;
void init()
{
for (int i = 2; i < MAX; i ++) {
if (!vis[i]) {
prime[cnt ++] = i;
}
for (int j = 0; j < cnt; j ++) {
if (i * prime[j] >= MAX) break;
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
}
void split(int x)
{
int t;
for (int i = 0; i < cnt; i ++) {
if (prime[i] * prime[i] > x) break;
t = 0;
while (x % prime[i] == 0) {
++ t;
x /= prime[i];
}
if (t)
m[prime[i]] |= (1 << (t - 1));
}
if (x > 1) {
m[x] |= 1;
}
}
void dfs_sg(int x)
{
if (sg.count(x)) return ;
int v[32];
memset(v, 0, sizeof v);
for (int i = 1; x >> (i - 1); i ++) {
int mask = (x >> i) | (x & ((1 << (i - 1)) - 1));
dfs_sg(mask);
v[sg[mask]] = 1;
}
for (int i = 0; ; i ++) {
if (!v[i]) {
sg[x] = i;
return ;
}
}
}
int main()
{
init();
int n, a, ans = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i ++) {
scanf("%d", &a);
split(a);
}
sg[0] = 0;
for (auto it = m.begin(); it != m.end(); it ++) {
dfs_sg(it -> second);
ans ^= sg[it -> second];
}
if (ans) {
puts("Mojtaba");
} else {
puts("Arpa");
}
return 0;
}