zoukankan      html  css  js  c++  java
  • JZYZOJ1540 BZOJ4035 [ haoi2015 上午] T3 博弈论 sg函数 分块 haoi

    http://172.20.6.3/Problem_Show.asp?id=1540

    之前莫比乌斯反演也写了一道这种找规律分块计算的题,没觉得这么恶心啊。

    具体解释看代码。

    翻硬币的具体方法就是分别算出每个单个正面朝上的情况的sg函数然后异或。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<iostream>
     6 #include<map>
     7 #include<ctime>
     8 using namespace std;
     9 int n,k,w,mx;
    10 int f[100010][2]={};//n/x和n/(n/x)代表的x的sg值,分成两部分使得储存需要的空间开根
    11 //值得注意的是,这两种划分方式分出的x的范围是一定的,大概是数字的性质。
    12 int vis[100010]={};
    13 int doit(int x,int y){return x==y?x+1:y/(y/(x+1));}
    14 int main(){
    15     scanf("%d%d",&n,&k);
    16     //暴力代码
    17     /*for(int i=n;i>=1;i--){
    18         int now=0;
    19         for(int j=i+i;j<=n;j+=i){
    20             now^=f[j];vis[now]=i;
    21         }
    22         for(int j=1;;j++){
    23             if(vis[j]!=i){
    24                 f[i]=j;
    25                 break;
    26             }
    27         }
    28     }*/
    29     /*暴力打表后可以发现这个东西满足规律:
    30         只要n/x(向下取整)相等sg值就相等。
    31         于是就开始了漫长艰辛的分块计算之旅  
    32         倒数真有趣
    33          _
    34         | |
    35         | |
    36      _ _| |_ _
    37     | | | | | |
    38     \_________/
    39     */
    40     mx=(int)sqrt(double(n));
    41     for(int i=1;i<=n;i=doit(i,n)){//这里枚举的i从小到大,其实是n/x
    42         int y,now=0,z;
    43         for(int j=2;j<=i;j=doit(j,i)){//上一层枚举了n/x,这一层用同样的方式枚举他的倍数
    44             y=i/j;//既然用n/x表达,扩大j倍自然是/j。
    45             z=y<=mx?f[y][0]:f[n/y][1];
    46             vis[now^z]=i;
    47             if((i/y-i/(y+1))&1)now^=z;
    48             //如果在范围里有偶数个z,那算下一个的范围的时候z就被自己消掉了所以不用算。
    49         }
    50         for(int j=1;;j++){//大家喜闻乐见的mex时间
    51             if(vis[j]!=i){
    52                 if(i<=mx)f[i][0]=j;else f[n/i][1]=j;
    53                 break;
    54             }
    55         }
    56     }
    57     for(int i=1;i<=k;i++){
    58         scanf("%d",&w);int x,ans=0;
    59         for(int i=1;i<=w;i++){
    60             scanf("%d",&x);
    61             x=n/x;
    62             ans^=x<=mx?f[x][0]:f[n/x][1];//喜闻乐见的异或时间
    63         }
    64         if(ans)printf("Yes
    ");//喜闻乐见的判定时间
    65         else printf("No
    ");
    66     }
    67     return 0;
    68 }
    View Code
  • 相关阅读:
    PHP如何获取内网IP
    开源的世界并不纯净
    在linux下玩上了第一人称射击
    终于,在linux下上网了
    我的理想
    vista是什么
    我傻了一阵子
    又是大端小端!!!
    谈谈最近的编程状态
    如何快速发布你的C++Builder程序
  • 原文地址:https://www.cnblogs.com/137shoebills/p/8335034.html
Copyright © 2011-2022 走看看