zoukankan      html  css  js  c++  java
  • 石子游戏(nim游戏+按位考虑)

    题意

    \(n\)堆石子,每次最多可以从一堆中取\(x\)个,问你\(x = 1 ... n\)时的答案。

    解法

    经典\(nim\)游戏,找规律知\(sg[i] = i \ mod \ (x+1)\)

    于是便要快速求\(a[1]\ mod\ (x+1) \bigoplus ... a[n]\ mod\ (x+1)\)

    考虑按位做,设\(y = x+1\),对于\(k \leq \frac{n}{y}\),求出\(x \in [ky,(k+1)y)\),求有多少\(x-ky\)\(2^j\)这一位。

    预处理出\(f_{j,i}\)表示对于\(x>=i\),有多少\(x-i\)\(2^j\)这一位,有

    \[f_{j,i} = f_{j,i+2^{j+1}} \ + \sum^{i+2^{j+1}-1}_{k = i+2^j} c_k \]

    其中\(c_i\)表示\(i\)出现的个数。

    考虑统计答案,答案一定是几个\(2^{j+1}\)长度的整块加上一个散块,对于整块,差分即可,对于散块,发现在\([0,2^j-1]\)之间的贡献是\(0\),在\([2^j,2^{j+1}-1]\)之间是\(1\),分\((k+1)y\)在左右半边讨论即可。

    code

    #include<bits/stdc++.h>
    #define ll long long
    #define N 500015
    #define rep(i,a,n) for (int i=a;i<=n;i++)
    #define per(i,a,n) for (int i=n;i>=a;i--)
    #define inf 0x3f3f3f3f
    #define pb push_back
    #define mp make_pair
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define lowbit(i) ((i)&(-i))
    #define VI vector<int>
    #define all(x) x.begin(),x.end()
    using namespace std;
    int c[N],f[21][N];
    int n;
    int main(){
    	//freopen(".in","r",stdin);
    	//freopen(".out","w",stdout);
     	scanf("%d",&n);
     	rep(i,1,n){
     		int u; scanf("%d",&u); c[u] ^= 1;
     	}
     	per(i,0,n) c[i] ^= c[i+1];
     	rep(j,0,18){ // f(j,i) 表示 对于所有x >= i ,x-i有j这一位的异或 是0/1
     		per(i,0,n){
     			if((i+(1<<j)) > n) f[j][i] = 0; //x-i 有j这一位 -> x-i > 2^j
     			else if((i+(1<<(j+1))) > n) f[j][i] = c[i+(1<<j)];
     			else f[j][i] = f[j][i+(1<<(j+1))]^c[i+(1<<(j+1))]^c[i+(1<<j)]; //
     		}
     	}
     	rep(i,2,n+1){
     		int top = n/i;//(mod i)
     		bool ff = 0;
     		rep(j,0,18){
     			if((1<<j) >= i) break;
     			bool now = 0;
     			rep(k,0,top){
     				int l = k*i; // [k*i,(k+1)*i)
     				int r = l+((((i-1)>>(j+1))+1)<<(j+1)); // l ~ i-1向上第一个2^(j+1)的倍数
     				now ^= f[j][l];
     				if(r <= n) now ^= f[j][r];
     				now ^= c[min(max(l+i,r-(1<<j)),n+1)]^c[min(r,n+1)];
     			}
     			if(now){ff = 1; break;}
     		}
     		if(ff) printf("Alice ");
     		else printf("Bob ");
     	}
    	return 0;
    }
    
  • 相关阅读:
    常用的正则表达式,字符串,地址操作
    倒计时工具
    Java—集合框架List
    Java—包装类、Date和SimpleDateFormat、Calendar类
    Java—字符串
    Java —异常
    Java—多态
    Java—继承
    Java—封装
    Java —类和对象
  • 原文地址:https://www.cnblogs.com/czdzx/p/14008017.html
Copyright © 2011-2022 走看看