Atcoder 212H Nim Counting

Problem Statement

Given are positive integers (N, K), and a sequence of K integers ((A_1,A_2,…,A_K)).

Takahashi and Aoki will play a game with stones. Initially, there are some heaps of stones, each of which contains one or more stones. The players take turns doing the following operation, with Takahashi going first.

  • Choose a heap with one or more stones remaining. Remove any number of stones between (1) and (X)(inclusive) from that heap, where (X) is the number of stones remaining.

The player who first gets unable to do the operation loses.

Now, consider the initial arrangements of stones satisfying the following.

  • (1≤M≤N) holds, where MM is the number of heaps of stones.
  • The number of stones in each heap is one of the following: (A_1,A_2,…,A_K).

Assuming that the heaps are ordered, there are (K+K_2+⋯+K_N) such initial arrangements of stones. Among them, find the number, modulo (998244353), of arrangements that lead to Takahashi's win, assuming that both players play optimally.

Constraints

  • (1≤N≤2×10^5)
  • (1≤K<2^{16})
  • (1≤A_i<2^{16})
  • All (A_i) are distinct.
  • All values in input are integers.

Input

Input is given from Standard Input in the following format:

N K
A1 A2 …… AK

Output

Print the answer.


Sample Input 1 Copy

Copy

2 2
1 2
Sample Output 1 Copy

Copy

4

There are six possible initial arrangements of stones: (1), (2), (1,1), (1,2), (2,1), and (2,2).
Takahashi has a winning strategy for four of them: (1), (2), (1,2), and (2,1), and Aoki has a winning strategy for the other two. Thus, we should print 4.


Sample Input 2 Copy

Copy

100 3
3 5 7
Sample Output 2 Copy

Copy

112184936

Be sure to find the count modulo 998244353.

题目翻译

2个人玩Nim取石子游戏,最多可以设计(N)堆石子,石子的数量可以在(a_i(1<=i<=K))中任意选择,石子堆数任意,求先手必胜方案数

题目分析

首先是Nim游戏总所周知的结论:先手必胜当且仅当每堆石子数量异或和不为0,即(b_1 igoplus b_2....igoplus b_m ot=0)

此题和BZOJ 4589 Hard Nim(不过BZOJ好像已经寄了)很像,不过是复杂版本,BZOJ是固定N堆,本题需要考虑不同堆数

此题首先确定递推式(Z_k=sum_{i⊕j=k}X_iY_j),初始的(X_i)(Y_i)当存在(i=a_?)时为(1)

利用快速沃尔什变换,将多项式异或乘法转换为向量乘法,通过令初始的多项式转换的向量为(C)计算(C^n)即可得到(n)堆石子不同异或和下的方案数。常规做法重载乘法进行快速幂即可

但是考虑到本题需要求的是(C^1+C^2+.....C^n),由于快速沃尔什变换后表达式已经变成向量的乘法,所以直接对(C)的每一项(C_i)计算(frac{C_i(1-C_{i}^{n})}{1-C_i})

最后进行逆变换即可求得每项系数为方案数的表达式,对(sum_{i=1}C_i)求和即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
int Mod = 998244353, inv2, n, k,Max;
int f[200005], a[200005],ans;
int qpow(int x, int y)
{
    int res = 1;
    while (y)
    {
        if (y & 1)
            res = 1ll * res * x % Mod;
        x = 1ll * x * x % Mod;
        y >>= 1;
    }
    return res;
}
void FWT(int *A, int len)
{
    int i, j, k;
    for (i = 1; i < len; i <<= 1)
    {
        for (j = 0; j < len; j += (i << 1))
        {
            for (k = 0; k < i; k++)
            {
                int x = A[j + k], y = A[j + k + i];
                A[j + k] = x + y;
                if (A[j + k] >= Mod)
                    A[j + k] -= Mod;
                A[j + k + i] = x - y;
                if (A[j + k + i] < 0)
                    A[j + k + i] += Mod;
            }
        }
    }
}
void UFWT(int *A, int len)
{
    int i, j, k;
    for (i = 1; i < len; i <<= 1)
    {
        for (j = 0; j < len; j += (i << 1))
        {
            for (k = 0; k < i; k++)
            {
                int x = A[j + k], y = A[j + k + i];
                A[j + k] = 1ll * (x + y) * inv2 % Mod;
                A[j + k + i] = 1ll * (x - y + Mod) * inv2 % Mod;
            }
        }
    }
}
int main()
{
    int len, i,x;
    inv2 = qpow(2, Mod - 2);
    memset(f, 0, sizeof(f));
    memset(a, 0, sizeof(a));
    cin>>n>>k;
    for (int i=1;i<=k;i++){
        scanf("%d",&x);
        Max=max(x,Max);
        a[x]=1;
    }
    len = 1;
    while (len <= Max)
        len *= 2;
    FWT(a, len);
    for (int i=0;i<len;i++){
        if (a[i]==0) continue;
        else if (a[i]==1) a[i]=n;
        else{
            ll x=a[i];
            a[i]=qpow(a[i],n)-1;
            a[i]=(a[i]*x)%Mod*qpow(x-1,Mod-2)%Mod;
        }
    }
    UFWT(a, len);
    for (int i=1;i<len;i++){
        ans=(ans+a[i])%Mod;
        //cout<<a[i]<<endl;
    }
    cout<<ans;
}
原文地址:https://www.cnblogs.com/Y-E-T-I/p/15133711.html