• 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
  • 相关阅读:
    【LOJ】#2888. 「APIO2015」巴邻旁之桥 Palembang Bridges
    【AtCoder】ARC099题解
    【LOJ】#2265. 「CTSC2017」最长上升子序列
    【LOJ】#2264. 「CTSC2017」吉夫特
    【AtCoder】AGC028 (A-E)题解
    【AtCoder】ARC100 题解
    【AtCoder】ARC101题解
    【AtCoder】AGC026 题解
    【LOJ】 #2308. 「APIO2017」商旅
    【BZOJ】3456: 城市规划(多项式求ln)
  • 原文地址:https://www.cnblogs.com/137shoebills/p/8335034.html
Copyright © 2020-2023  润新知