原题链接

题意简述

给出一个n(n≤105)个数的序列a,足够聪明的AB两人轮流进行以下操作:

令一个大于1的数减1,然后所有数除以gcd{a}。

如果一个人不能操作了,那么他就输了。

输入保证所有数都是正整数并且gcd{a}=1。

分析

这是一道和奇偶性有关的题目。

很容易知道拿到1,1,1,...,1就输了,此时手里数的和sum等于n。

考虑sum奇偶性的转换关系。

或者再展开一点:

偶-奇必然的很好理解,重点考虑一下sum为奇数的情形。

奇(-偶)-奇 要求gcd为偶数,因为偶/奇=偶。因此原数列%2必然是000…01的形式,而我可以将其变为000…11从而形成奇-偶 。所以奇-奇一定条件下可选的,奇-偶任何条件下可行的。

由此再考虑n的奇偶性对答案的影响。

  1. n为偶数

    能保持sum为奇数的一方一定不会输。既然sum一直是奇数,那么就一定不会得到1,1,1,...,1的状态,必胜。而因为拿到奇数的一方一定可以给对手一个偶数,而对手只能无可奈何地还你一个奇数。所以初始sum为奇数则先手必胜,否则必败。

    时间复杂度为O(n)。
  2. n为奇数

    能保持sum为偶数的一方一定不会输。但是拿到偶数的一方需要保证对手不会还回来一个奇数,下面证明这一点一定可以做到。

    证明

    首先奇数方要是想还给对手一个奇数必然要使gcd不为1,所以原数列%gcd必然是000…01的形式。再考虑这个状态是怎么达到的:



    对于000…11,000…02,000…1k,000…0(k+1)这四种状态另一方都有办法规避000…01的结果。所以拿到偶数的一方一定能保证下一轮自己还是偶数。

    因此初始sum为偶数的话先手必胜。

    时间复杂度为O(n)。

    但是初始sum是奇数并不意味着必败;因为此时还没有另一方的干扰,是有可能给对手一个奇数的。但是由于你可能只有极少的选择方案,这给了对手可乘之机:对手也有可能还回来一个奇数。以此循环往复,无法给对手奇数的一方会输掉游戏。

    因为每次都会给所有数除以一个大于1的gcd,所以最多往复log2(min{a})次,其中每次操作的复杂度是O(n)。时间复杂度最大为O(n⋅log2(min{a}))。

总时间复杂度最大为O(n⋅log2(min{a}))。

实现

只有n,sum均为奇数时无法通过判断n和sum的奇偶性来得出答案。

计算出前缀gcdg1和后缀gcdg2,然后计算gcd{g1[i−1],a[i]−1,g2[i+1]},如果 (sum−1)/gcd 为奇数就令所有数除以gcd,然后轮到对手。若没有可能的gcd,GG。

代码

//Decrementing
#include <cstdio>
typedef long long lint;
int const N=1e5+10;
int n,a[N];
int gcd(int x,int y)
{
if(x==-1 || y==-1) return -x*y;
if(x==0) return y;
else return gcd(y%x,x);
}
int g1[N],g2[N];
int main()
{
scanf("%d",&n);
lint sum=0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum+=a[i];
if(n%2==0)
{
if(sum%2==1) printf("First");
else printf("Second");
return 0;
}
if(sum%2==0) {printf("First"); return 0;}
int cur=0;
while(true)
{
bool flag=false;
sum=0;
for(int i=1;i<=n;i++) sum+=a[i];
g1[0]=-1; g2[n+1]=-1;
for(int i=2;i<=n;i++) g1[i]=gcd(g1[i-1],a[i]);
for(int i=n-1;i>=1;i--) g2[i]=gcd(g2[i+1],a[i]);
int g;
for(int i=1;i<=n&&!flag;i++)
{
if(a[i]==1) continue;
g=gcd(gcd(g1[i-1],g2[i+1]),a[i]-1);
if(((sum-1)/g)%2==1) flag=true;
}
if(flag)
for(int i=1;i<=n;i++) a[i]/=g;
else
{
if(cur==0) printf("Second");
else printf("First");
return 0;
}
cur^=1;
}
return 0;
}

注意

挺好写的,主要是思维难度高

AGC010 - D: Decrementing的更多相关文章

  1. 【AtCoder】AGC010

    AGC010 A - Addition 如果所有数加起来是偶数那么一定可以,否则不行 #include <bits/stdc++.h> #define fi first #define s ...

  2. Agc010_D Decrementing

    今天本人因调了上篇博客的题而脑壳不适,不想颓题,因此有了这篇博客. 但是博客毕竟得讲点什么,想想有没有什么代码短的. 哦,好像有,就Agc010_D Decrementing好了. Alice和Bob ...

  3. [AtCoderContest010D]Decrementing

    [AtCoderContest010D]Decrementing 试题描述 There are \(N\) integers written on a blackboard. The \(i\)-th ...

  4. AGC010

    AGC010 A [过水已隐藏] B 这题推完了还是不会/kk真的毒瘤 考虑每次会减少的总和是\(n(n+1)/2\),用原来的和除以这个可以得到操作次数\(m\)(不是整数无解) 再考虑相邻两个数\ ...

  5. AGC010 - C: Cleaning

    原题链接 题意简述 给出一棵个节点的树,每个点有点权.每次可以选择两个叶节点并将连接它们的路径上的节点的点权-1(包括叶节点).求能否将所有节点的点权都变为0. 分析 先考虑最简单的情况.在这种情况下 ...

  6. AGC010 - B: Boxes

    原题链接 题意简述 给出一个由个数构成的环,每次可以选择一个位置并从这个数起顺时针依次对每个数-1,-2,-3,-,-n.问能否将所有数全变为0. 分析 考虑一次操作对环带来了什么影响. (在后加一个 ...

  7. AGC010 - A: Addition

    原题链接 题意简述 给出一个个数的数列,每次选出两个奇偶性相同的数合成一个数,问最终能否只剩下一个数. 分析 非常简单的一道题. 两个偶数可以合成一个偶数,两个奇数也能合成一个偶数.所以合并偶数时偶数 ...

  8. AGC 010D.Decrementing(博弈)

    题目链接 \(Description\) 给定\(n\)个数\(A_i\),且这\(n\)个数的\(GCD\)为\(1\).两个人轮流进行如下操作: 选择一个\(>1\)的数使它\(-1\). ...

  9. 【AGC010D】Decrementing

    Solution 日常博弈论做不出来. 首先,数值全部为1的局面先手必败. 在接下来的过程中,我们只关注那些大于1的数值. 按照官方题解的思路,首先想一个简化版的问题:没有除的操作,其余相同.那么局面 ...

随机推荐

  1. Servlet--取得session,application内置对象

    在前面的博客里面,使用Servlet取得了request,response,config对象,实际上通过Servlet程序也可以取得session,application等内置对象. 1,通过Http ...

  2. [搬运] .NET Core 2.1中改进的堆栈信息

    原文 : Stacktrace improvements in .NET Core 2.1 作者 : Ben Adams 译者 : 张很水 . NET Core 2.1 现在具有可读的异步堆栈信息!使 ...

  3. awk的批量replace功能

    awk的批量replace功能 需求 现在需要替换一个文本 文本内容如下 $cat file MD_D1TS_1_060_I MD_D1TS_1_061_F MD_D1TS_1_062_U MD_D1 ...

  4. all,any函数

    all函数:当矩阵全为非零元素时返回1,否则(存在零元素),返回0: any函数:当矩阵中存在非零      1     1     1     1      1     1     1     1 ...

  5. *C语言有关指针的变量声明中的几个易错点

    转至:http://my.oschina.net/ypimgt/blog/108265   Technorati 标签:  指针, typedef, const, define 我们都知道,至少听说过 ...

  6. win10下配置php环境变量

    下载php,解压. 比如解压到E盘,目录为"E:\PHP". 打开php目录,复制一个php.ini-development文件,改名为php.ini. 打开php.ini,将 e ...

  7. 07_Python变量内存地址、小数据池

    一.变量在内存中的地址 变量:用来标识(identify)一块内存区域.为了方便表示内存,我们操作变量实质上是在操作变量指向的那块内存单元.编译器负责分配.我们可以使用Python内建函数id()来获 ...

  8. Swing小技巧总结

    1. 使JDialog位于屏幕的中央 public void setToScreenCenter(JDialog jd) {           Dimension screenSize = Tool ...

  9. bzoj 4822: [Cqoi2017]老C的任务

    4822: [Cqoi2017]老C的任务 练手速... #include <iostream> #include <cstdio> #include <cstring& ...

  10. 小甲鱼OD学习第2讲

    这次我们的任务是让我们输入任意用户名密码判断正确 我们输入fishc和111111,显示错误 我们猜测这是用GetDlgItemTextW来收集账号密码的输入值 我们找到了两个函数,给这两个函数都下断 ...