zoukankan      html  css  js  c++  java
  • AtCoder Grand Contest 010 D

    题目传送门:https://agc010.contest.atcoder.jp/tasks/agc010_d

    题目大意:
    (n)个数(A_i),它们的(gcd)是1,A、B两人轮流操作,每人每次可以进行一次操作(以下两步算一次操作):

    • 选取一个大于1的数减1
    • 将所有数除以它们的(gcd)

    当所有数都为1时,不能操作的人为输,问先手能否必胜?


    博弈论好题,我们可以发现一些性质:

    • 如果序列存在一个1,那么偶数个数为奇数则先手必胜,否则先手必败(显然)
    • 如果序列中有奇数个偶数,则先手必胜(先手可以利用初始的一个奇数((gcd)为1),保证序列中存在两个奇数,使得序列每次只能减1)
    • 如果奇数个数大于1,且偶数个数为偶数,那么先手必败(有多个奇数,任意选一个后(gcd)仍然为1,变为情况2)
    • 其他情况让奇数减一,然后序列整体除(gcd),递归即可
    /*problem from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    #define lowbit(x) ((x)&-(x))
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline char gc(){
    	static char buf[1000000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int frd(){
    	int x=0,f=1; char ch=gc();
    	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline int read(){
    	int x=0,f=1; char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x<0)	putchar('-');
    	if (x>9)	print(x/10);
    	putchar(x%10+'0');
    }
    const int N=1e5;
    int v[N+10];
    int gcd(int a,int b){return !b?a:gcd(b,a%b);}
    int check(int n){
    	int odd=0,even=0; bool flag=0;
    	for (int i=1;i<=n;i++){
    		v[i]&1?odd++:even++;
    		if (v[i]==1)	flag=1,odd--;
    	}
    	if (even&1)	return 1;
    	if (flag)	return 0;
    	if (odd>1)	return 0;
    	return -1;
    }
    int main(){
    	int n=read(),Time=0;
    	for (int i=1;i<=n;i++)	v[i]=read();
    	while (true){
    		int tmp=check(n),d=0; ++Time;
    		if (~tmp){
    			printf((tmp^Time)&1?"Second
    ":"First
    ");
    			break;
    		}
    		for (int i=1;i<=n;i++)	if (v[i]&1)	v[i]--;
    		for (int i=1;i<=n;i++)	d=gcd(d,v[i]);
    		for (int i=1;i<=n;i++)	v[i]/=d;
    	}
    	return 0;
    }
    
  • 相关阅读:
    Leetcode 1489找到最小生成树李关键边和伪关键边
    Leetcode 113 路径总和 II
    hdu 1223 还是畅通工程
    hdu 1087 Super Jumping! Jumping! Jumping!
    hdu 1008 Elevator
    hdu 1037 Keep on Truckin'
    湖工oj 1241 畅通工程
    湖工oj 1162 大武汉局域网
    hdu 2057 A + B Again
    poj 2236 Wireless Network
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/10071695.html
Copyright © 2011-2022 走看看