• 2018牛客网暑假ACM多校训练赛(第八场)H Playing games 博弈 FWT


    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round8-H.html

    题目传送门 - https://www.nowcoder.com/acm/contest/146/H

    题意

      有 $n$ 堆石子,第 $i$ 堆有 $a_i$ 个。请你取出尽量多堆石子,使得取石子nim游戏后手必胜。输出你选择的石子堆数。

      $n,a_ileq 5 imes 10^5$

    题解

      首先我们把题转化成:在 $n$ 个数中选择尽量多的数,使得他们的异或值为 $0$ 。

      然后我们把题转化成:在 $n$ 个数中选择尽量少的数,使得他们的异或值为一个特定值 $C$ 。其中 $C=a_1 { m XOR} cdots { m XOR} a_n$ 。显然,答案为 $n-$ 你选择的数的个数。

      考虑将 $a_i$ 二进制的每一维拆开,看作一个 $d$ 维向量。其中由于 $a_ileq 2^{19}$,所以我们取 $d=19$ 。

      由于 $d$ 维线性无关向量组最多有 $n$ 个向量,所以我们最多在那些数字里面取 $d$ 个。

      我们考虑二分答案,假设选择小于等于 $k$ 个就可以组成 $C$ 了。

      我们如何验证:

      对于原数组每一个数出现的位置都记一下,然后把位置 $0$ 也搞一下,然后取它在异或卷积意义下的 $k$ 次幂,判断一下可不可以合成 $C$ 即可。这个用 FWT 做。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int read(){
    	int x=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+ch-48,ch=getchar();
    	return x;
    }
    const int N=1<<19,mod=1e9+7,inv2=5e8+4;
    int n,a[N],b[N],v=0;
    int Pow(int x,int y){
    	int ans=1;
    	for (;y;y>>=1,x=1LL*x*x%mod)
    		if (y&1)
    			ans=1LL*ans*x%mod;
    	return ans;
    }
    void FWT(int a[],int n,int flag){
    	for (int d=1;d<n;d<<=1)
    		for (int i=0;i<n;i+=(d<<1))
    			for (int j=0;j<d;j++){
    				int x=a[i+j],y=a[i+j+d];
    				a[i+j]=(x+y)%mod;
    				a[i+j+d]=(x-y)%mod;
    				if (flag==-1){
    					a[i+j]=1LL*a[i+j]*inv2%mod;
    					a[i+j+d]=1LL*a[i+j+d]*inv2%mod;
    				}
    			}
    }
    bool check(int x,int n){
    	for (int i=0;i<n;i++)
    		b[i]=Pow(a[i],x);
    	FWT(b,n,-1);
    	b[v]=(b[v]+mod)%mod;
    	return b[v]>0;
    }
    int main(){
    	n=read();
    	memset(a,0,sizeof a);
    	for (int i=1;i<=n;i++){
    		int x=read();
    		v^=x;
    		a[x]++;
    	}
    	a[0]++;
    	int m=1<<19;
    	FWT(a,m,1);
    	int L=0,R=19,mid,ans=19;
    	while (L<=R){
    		mid=(L+R)>>1;
    		if (check(mid,m))
    			R=mid-1,ans=mid;
    		else
    			L=mid+1;
    	}
    	printf("%d
    ",n-ans);
    	return 0;
    }
    

      

  • 相关阅读:
    C语言II作业01
    C语言寒假大作战04
    C语言寒假大作战03
    C语言寒假大作战02
    C语言寒假大作战01
    C语言I博客作业12—学期总结
    第一次作业
    C语言I博客作业02
    C语言I博客作业11
    C语言||作业01
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round8-H.html
Copyright © 2020-2023  润新知