zoukankan      html  css  js  c++  java
  • luogu P3235 [HNOI2014]江南乐

    传送门

    这题又是我什么时候做的(挠头)

    首先是个和SG函数有关的博弈论,SG=0则先手必败.显然一堆石子就是一个游戏,而若干堆石子的SG值就是每堆SG的异或和,所以算出每堆石子SG就能知道答案

    然后怎么求SG,根据定义,一个局面SG是后继局面SG的(mex),我们枚举某堆石子(有x个)分成多少堆i,然后能知道有若干堆石子有(lfloorfrac{x}{i} floor)个,还有的有(lceilfrac{x}{i} ceil)个.然后这两种石子的堆数也可以算出来,又因为异或某个数偶数次=0,所以只要分奇偶性看是否异或就好了.

    上述过程可以加记忆化优化.但是暴力枚举还是不行的,注意到(lfloorfrac{x}{i} floor)最多只有(2sqrt n)种取值,所以可以参考数论分块的做法,对于(lfloorfrac{x}{i} floor)相同的一些(i),只要计算最小的(i)以及(i+1),因为更大的(i)的贡献和(i)(i+1)中某一个是相同的

    #include<bits/stdc++.h>
    #define LL long long
    #define db double
    #define il inline
    #define re register
    
    using namespace std;
    const int N=1e5+10;
    il int rd()
    {
      int x=0,w=1;char ch=0;
      while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
      while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
      return x*w;
    }
    int sg[N],mm[N];
    int t,f,n;
    il int sov(int o)
    {
      if(o<f) return 0;
      if(~sg[o]) return sg[o];
      sg[o]=0;
      for(int i=2;i<=o;i=o/(o/i)+1)
        {
          int xx=0;
          if((o%i)&1) xx^=sov(o/i+1);
          if((i-o%i)&1) xx^=sov(o/i);
          mm[xx]=o;
          if(i==o) continue;
          xx=0,++i;
          if((o%i)&1) xx^=sov(o/i+1);
          if((i-o%i)&1) xx^=sov(o/i);
          mm[xx]=o,--i;
        }
      while(mm[sg[o]]==o) ++sg[o];
      return sg[o];
    }
    
    int main()
    {
      t=rd(),f=rd();
      memset(sg,-1,sizeof(sg));
      while(t--)
        {
          int n=rd(),an=0;
          while(n--) an^=sov(rd());
          printf("%d ",an>0);
        }
      return 0;
    }
    
  • 相关阅读:
    stm32时钟分析
    STM32中断优先级彻底讲解
    STM32 外部中断简介
    sencha touch 选择器
    sench touch 页面跳转
    sencha touch 学习汇总(转)
    ES6项目构建(babel+gulp+webpack)
    sencha touch
    sencha touch 目录结构
    angular学习笔记(6)- 指令
  • 原文地址:https://www.cnblogs.com/smyjr/p/10415684.html
Copyright © 2011-2022 走看看