zoukankan      html  css  js  c++  java
  • 江南乐 题解

    首先我们要知道 (SG) 定理: (SG_{tot} = SG_1 xor SG_2 xor SG_3 xor ... xor SG_n)
    所以我们可以预处理出1到100000中每个数的 (SG) 值,对于每一个询问,我们只需求一下 (SG_{tot}) 就好了。
    那怎么预处理出每一个数的 (SG) 值呢?
    对于某一堆 (i) ,有 (i) 个石子,我们可以枚举分成的堆数 (m (2 le m le i)) 。设分成 (m) 堆后, 每堆的石子个数为 $ x_i $ , 我们求出$ SG[x_i] $ 的异或和 $ res $ ,就是分成 (m) 堆后的状态的 (SG) 值,然后取 (mex) 运算得出当前状态 (i)(SG) 值。
    可这太暴力了,时间复杂度是 (O(n^2))的,70分,考虑优化。
    我们可以发现分成的 (m) 堆的石子数最多有两种取值,分别是: (i / m, (i / m) + 1)。这两种取值的个数分别是: (i \% m , m - i\%m)
    再考虑有贡献的值,因为求的是 $ SG $ 的异或和,所以只有某个取值的个数为奇数个时,才有贡献。接下来只需判断两种取值的个数的奇偶性就好了。
    举个例子:(i = 9)

    m :     2 3 4 5 6 7 8 9
    i / m : 4 3 2 1 1 1 1 1
    

    可以发现 (m) 从5到9, (i / m) 值是相同的,对于某些不同的 $ m$ , $i / m $ 的值相同,就可以用整除分块做。我们把后面分的石子堆数都列出来:

    5 : 2 2 2 2 1           
    6 : 2 2 2 1 1 1
    7 : 2 2 1 1 1 1 1
    8 : 2 1 1 1 1 1 1 1
    9 : 1 1 1 1 1 1 1 1 1
    

    可以发现某一个数目的石子堆数的奇偶性是一定的,证明:多举几个例子就好了

    ​ 当 (egin{aligned}frac{i} { m}end{aligned})为奇数时,(egin{aligned}m -i\%m = m - (i- m imeslfloor frac{i}{m} floor)=m imes (1+lfloor frac{i}{m} floor)-iend{aligned}),对于(egin{aligned}1+lfloor frac{i}{m} floorend{aligned})为偶数,(m + 1)后,奇偶性不变

    ​ 当 (egin{aligned}frac{i} { m}end{aligned})为偶数时,(egin{aligned}i\%m = i- m imeslfloor frac{i}{m} floorend{aligned})(m + 1)后,奇偶性不变

    ​ 所以对于 (i / m) 相等的块内,分出的石子数的两种取值的奇偶性的组合只有两种(有点绕,好好想想),所以对于一整块内只需算出这两种不同的 $ SG $ 异或和就好了,因为取 (mex) 运算不需要判断重复的值。第一种和第二种一定可以算出所有不同的 $ SG $ 异或和的值,算前两种就好了。

    #include <bits/stdc++.h>
        
    using namespace std;
        
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
        
    const int N = 105, M = 1e5 + 5;
    int T, F, n;
    int a[N], SG[M], vis[N];
    
    int main() {
        
        T = read(); F = read();
    // 1 到 F-1 先手必输,SG数组的值为0
        for(int i = F;i <= M - 5; i++) {
            int r;
            for(int j = 2;j <= i; j = r + 1) {
                int t = i / j;
                r = i / (i / j);
                int flag;
                if(j == r) flag = 1; // 如果i/m值相等的只有一个数,那就不需要算两遍了
                else flag = 2;
                int num = 0, res = 0;
                while(num < flag) {
                    num++;
                    res = 0;
                    if((i % j) & 1) 
                        res ^= SG[t + 1];
                    if((j - i % j) & 1) 
                        res ^= SG[t];
                    j++;
                    vis[res] = i;
                }
            }
            for(int j = 0; ; j++) 
                if(vis[j] != i) { 
                    SG[i] = j; break;
                }
        }
    
        while(T --> 0) {
            n = read(); 
            int res = 0;
            for(int i = 1;i <= n; i++) {
                a[i] = read();
                res ^= SG[a[i]];
            }
            if(res == 0) printf("0 ");
            else printf("1 ");
        }
    
        return 0;
    }
    
  • 相关阅读:
    Codeforces Round #592 (Div. 2)C. The Football Season(暴力,循环节)
    Educational Codeforces Round 72 (Rated for Div. 2)D. Coloring Edges(想法)
    扩展KMP
    poj 1699 Best Sequence(dfs)
    KMP(思路分析)
    poj 1950 Dessert(dfs)
    poj 3278 Catch That Cow(BFS)
    素数环(回溯)
    sort与qsort
    poj 1952 buy low buy lower(DP)
  • 原文地址:https://www.cnblogs.com/Aswert/p/13610737.html
Copyright © 2011-2022 走看看