[Codeforces 850C]Arpa and a game with Mojtaba

Description

题库链接

两个人 Van♂ 游戏。给出 \(n\) 个正整数 \(a_i\) 。两人轮流操作,每次选出一个素数 \(p\) 和一个幂数 \(k\) ,选择的前提为该 \(n\) 个数中有 \(p^k\) 的倍数。接着将所有的 \(p^k\) 的倍数除以 \(p^k\) 。变成新的序列,继续操作。不能操作者为败,问先手是否必胜。

\(1\leq 100\leq n,1\leq a_i\leq 10^9\)

Solution

首先显然的是不同的素数间是不会互相影响的。显然这个问题就变成了若干个质数组成的组合游戏。

我们可以单独讨论每一个素数。而对于这个素数相同的次幂。是可以看成同一个的,我们可以用二进制压下所有的幂次是否存在。

那么对于一个状态我们可以枚举合法的 \(k\) ,更新状态之后可以继续递归求解。

记忆化搜索实现。

Code

//It is made by Awson on 2018.3.14
#include <bits/stdc++.h>
#define LL long long
#define dob complex<double>
#define Abs(a) ((a) < 0 ? (-(a)) : (a))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
#define writeln(x) (write(x), putchar('\n'))
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int N = 1e5;
void read(int &x) {
    char ch; bool flag = 0;
    for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
    for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
    x *= 1-2*flag;
}
void print(LL x) {if (x > 9) print(x/10); putchar(x%10+48); }
void write(LL x) {if (x < 0) putchar('-'); print(Abs(x)); }

int n, prime[N+5], tot, is[N+5], bin[35], a;
map<int, int>sg, st;

void get_prime() {
    memset(is, 1, sizeof(is)); is[1] = 0;
    for (int i = 2; i <= N; i++) {
    if (is[i]) prime[++tot] = i;
    for (int j = 1; j <= tot && prime[j]*i <= N; j++) {
        is[i*prime[j]] = 0;
        if (i%prime[j] == 0) break;
    }
    }
}
void pre(int x) {
    for (int i = 1; i <= tot && 1ll*prime[i]*prime[i] <= x; i++) {
    int t = 0;
    while (x%prime[i] == 0) ++t, x /= prime[i];
    if (t) st[prime[i]] |= bin[t-1];
    }
    if (x != 1) st[x] |= bin[0];
}
int f(int x) {
    if (x == 0) return 0;
    if (sg.count(x)) return sg[x];
    sg[x] = 0; map<int, int>vis;
    int p = x, t = 0; while (p) p >>= 1, ++t;
    for (int i = 1; i <= t; i++) vis[f((x>>i)|(x&(bin[i-1]-1)))] = 1;
    while (vis.count(sg[x])) ++sg[x];
    return sg[x];
}
void work() {
    read(n); get_prime();
    bin[0] = 1; for (int i = 1; i <= 30; i++) bin[i] = bin[i-1]<<1;
    for (int i = 1; i <= n; i++) read(a), pre(a);
    int ans = 0;
    for (map<int, int>::iterator it = st.begin(); it != st.end(); it++) ans ^= f(it->second);
    puts(ans ? "Mojtaba" : "Arpa");
}
int main() {
    work(); return 0;
}

原文地址:https://www.cnblogs.com/NaVi-Awson/p/8567712.html

时间: 2024-10-08 01:18:33

[Codeforces 850C]Arpa and a game with Mojtaba的相关文章

Codeforces 741B Arpa&#39;s weak amphitheater and Mehrdad&#39;s valuable Hoses

[题目链接] http://codeforces.com/problemset/problem/741/B [题目大意] 给出一张图,所有连通块构成分组,每个点有价值和代价, 要么选择整个连通块,要么只能在连通块中选择一个,或者不选,为最大价值 [题解] 首先我们用并查集求出连通块,然后对连通块进行分组背包即可. [代码] #include <cstdio> #include <vector> #include <algorithm> #include <cstr

codeforces 742D Arpa&#39;s weak amphitheater and Mehrdad&#39;s valuable Hoses ——(01背包变形)

题意:给你若干个集合,每个集合内的物品要么选任意一个,要么所有都选,求最后在背包能容纳的范围下最大的价值. 分析:对于每个并查集,从上到下滚动维护即可,其实就是一个01背包= =. 代码如下: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <vector> 5 using namespace std; 6 const int N = 1000 + 5;

codeforces 851D Arpa and a list of numbers

目录 codeforces 851D Arpa and a list of numbers 题意 题解 Code codeforces 851D Arpa and a list of numbers 题目传送门 题意 给出\(n\)个数,有两种操作: 1.将一个数从数列中删除,代价为\(x\). 2.将一个数加1,代价为\(y\). 询问最少花费多少的代价能够使数列中所有数的\(Gcd\)不为1. \((1 \leq n \leq 5 \cdot 10^5 , 1 \leq x,y \leq 1

Codeforces 850C E. Arpa and a game with Mojtaba

对每个数统计其素数因子各次方数的数,然后通过y = (x>>i) | (x&((1<<(i-1))-1)) 模拟delete x and add  to the list 操作,用grund函数将每个因子的情况映射为NIM问题中一个堆的情况,再按NIM问题的求解方法求解 参考链接 https://www.topcoder.com/community/data-science/data-science-tutorials/algorithm-games/ #include&l

[CodeForces850C]Arpa and a game with Mojtaba

题目大意: 给你一个包含n个数的数列,两个人轮流对数列进行如下操作: 选择一个质数p和一个正整数k,将数列中所有能被p^k整除的数除以p^k. 最后不能操作者负. 问先手是否有必胜策略. 思路: 显然,结果不直接与数列中数的值有关,而与数列中每个数的质因数及其次数有关,因此我们可以将每个质因数分开考虑. 枚举数列中出现的每一个质因数p,对数列中的数除去p^k就相当于将p对应的次数减去k. 如果不同的数对于同一个质因数p,对应的次数相同,那么无论除去p的几次,对于这两个数的影响都是一样的. 那么我

【Codeforces 851D Arpa and a list of numbers】

Arpa的数列要根据GCD变成好数列. ·英文题,述大意:      给出一个长度为n(n<=5000000)的序列,其中的元素a[i]<=106,然后输入两个数x,y(x,y<=109)现在有两种操作:①支付x的代价删除一个数.②支付y的代价将一个数加1.题目要求支付最少的代价,使得原序列所有元素的GCD不为1. ·分析:      GCD不为1?那么就是说每个数至少有一个共同的非1因子.使所有数拥有同一个因子一定比使它们拥有两个相同因子容易,所以题目其实要求我们完成这个任务:对于某个

CodeForces 742B Arpa’s obvious problem and Mehrdad’s terrible solution (暴力枚举)

题意:求定 n 个数,求有多少对数满足,ai^bi = x. 析:暴力枚举就行,n的复杂度. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <c

CodeForces 742A Arpa’s hard exam and Mehrdad’s naive cheat

题意:求1378 n次幂的最后一位. 析:两种方法,第一种,就是快速幂,第二种找循环节,也很好找,求一下前几个数就好. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #

CodeForces - 742B Arpa’s obvious problem and Mehrdad’s terrible solution

假期训练的一道题,用了一些异或的一些性质1^2=3,3^1=2,3^2=1 就是相当于反向异或运算然后查找个数. 提供一组样例 5 0 1 1 1 1 1 这就是用long long的原因 下面是代码 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e6+5; 4 typedef long long ll; 5 int b[maxn], n, x; 6 7 int main() 8 { 9 while(~