• [AGC002 E]Candy Piles


    题意

    给一个(n)个元素的数组(a_i),每次可以有两种操作:

    • 将所有数中最大的那个数整个删除
    • 将所有数减(1),如果减到(0)就删除

    问如果两个人轮番操作,到最后谁不能进行操作了就输,问谁能赢。

    • (1leq Nleq 10^5)
    • (1leq a_i leq 10^9)

    分析

    我们考虑,将整个数组从大到小排序,然后考虑像这样可以画出一个图表一样的东西,那么就必然每次删最大相当于是将最左边的删掉。然后我们考虑全部数减(1)的操作,这相当于是将最下面一行删掉。这个时候这个游戏就变成了一个更加简洁的东西:给一条单调不增的折线,每次可以往上和往右走,走到边界的时候输,问怎样胜利。这个问题很显然可以设例如在先手的视角,对于某一个坐标((x,y)),设出一个判定函数(f(x,y))表示从((x,y))出发是必胜还是必败。很好写出转移,当((x+1,y))((x,y+1))两个中存在一个必败的,那当前这个就是必胜的(只要走到那个必败的格子,后手就必败),反之当前格子必胜。

    这样暴力计算显然是( ext O(sum a_i))的,复杂度爆炸所以没啥用= =但是你要是打个表出来,你会发现一个奇妙的规律:从((0,0))((1,1))(cdots)((v,v))一直都是同样的一个胜利情况!我们考虑这个结论其实同样很容易看出,考虑对于某一方,如果任意一个((x+1,y+1))是必败状态,那么((x,y+1))((x+1,y))都是必胜状态,进一步((x,y))是必败状态。于是我们可以推出,在对这一方来说,这样一条斜向上的线上面的胜负状态都是一样的,那么对于另一方因为是刚好反过来所以也是一样的。

    我们考虑,我们走某个点刚好顶住了,这时我们可能有两种方式:一种是往上走,一种是往右走。这两个都很容易计算,我们只要看一下往两个方向走能够顶到什么点,那个点的胜负状态是怎样的就可算出答案,整体复杂度也显然是( ext O(N))的。

    # include <bits/stdc++.h>
    # define rep(i,a,b) for(int i=a;i<=b;++i)
    using namespace std;
    const int maxn = 100010;
    int read(){
    	char c=getchar(); int x=0;
    	for(;c<'0'||c>'9';c=getchar());
    	for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
    	return x;
    }
    int a[maxn];
    int n;
    int main(){
    	n=read();
    	rep(i,0,n-1)a[i]=read();
    	sort(a+0,a+n);
    	reverse(a+0,a+n);
    	int p=0,y=0;
    	for(;p+1<n&&a[p+1]>p+1;++p);
    	for(;y<n&&a[y]>p;++y);
    	if ((a[p]-p)&1 && (y-p)&1) puts("Second");
    	else puts("First");
    	return 0;
    }
    
  • 相关阅读:
    Sql Server字符串拆分(Split)方法汇总
    Raid0、Raid1、Raid0+1、Raid3和Raid5 几种磁盘阵列区别
    浅谈sql优化
    python 多进程和异步io的有机结合 Error in atexit._run_exitfuncs
    asp.net.core学习笔记1:swagger的使用和webapi接收Jobject对象
    在windows服务中托管asp.net.core
    人脸识别:face_recognition初尝试
    python 快速搭建局域网文件服务器 SimpleHTTPServer http.server
    sso和oauth2.0的简单了解学习
    python常用删除库的方法
  • 原文地址:https://www.cnblogs.com/wendavid/p/8991461.html
Copyright © 2020-2023  润新知