牛客2018暑假多校训练八-H(fwt)

链接:https://www.nowcoder.com/acm/contest/146/H
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

Niuniu likes playing games. He has n piles of stones. The i-th pile has ai stones. He wants to play with his good friend, UinUin. Niuniu can choose some piles out of the n piles. They will play with the chosen piles of stones. UinUin takes the first move. They take turns removing at least one stone from one chosen pile. The player who removes the last stone from the chosen piles wins the game. Niuniu wants to choose the maximum number of piles so that he can make sure he wins the game. Can you help Niuniu choose the piles?

输入描述:

 

The first line contains one integer n (1 ≤ n ≤ 500000), which means the number of piles.
The second line describes the piles, containing n non-negative integers, a1 a2 … an, separated by a space. The integers are less than or equal to 500000.

输出描述:

Print a single line with one number, which is the maximum number of piles Niuniu can choose to make sure he wins. If Niuniu cannot always win whatever piles he chooses, print 0.

示例1

输入

复制

8
1 9 2 6 0 8 1 7

输出

复制

7

说明

Niuniu can choose the piles {1,9,6,0,8,1,7} to make sure he wins the game.

题意:给出长度为n的一个数组,求出最多取几个数能使得他们的异或和为0.

思路:我们去寻找最少取几个数使得他们的异或和等于全部的异或和sum。ai最大为2^19,可以拆成19维的向量,由于每一维只有方向没有长度,n维空间中最多有n个线性无关向量,所以最多取19个向量就可一组合成sum,二分一下就可以。通过fwt加速。

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 6e5+10;
int a[maxn],b[maxn];
int sum;
ll rev = 5e8+4;
void FWT(int a[],int n)
{
    for(int d=1;d<n;d<<=1)
        for(int m=d<<1,i=0;i<n;i+=m)
            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)%mod;
                //xor:a[i+j]=x+y,a[i+j+d]=x-y;
                //and:a[i+j]=x+y;
                //or:a[i+j+d]=x+y;
            }
}
 
void UFWT(int a[],int n)
{
    for(int d=1;d<n;d<<=1)
        for(int m=d<<1,i=0;i<n;i+=m)
            for(int j=0;j<d;j++)
            {
                int x=a[i+j],y=a[i+j+d];
                a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod;
                //xor:a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;
                //and:a[i+j]=x-y;
                //or:a[i+j+d]=y-x;
            }
}
void solve(int a[],int b[],int n)
{
    FWT(a,n);
    FWT(b,n);
    for(int i=0;i<n;i++) a[i]=1LL*a[i]*b[i]%mod;
    UFWT(a,n);
}
int quick_pow(int a,int b)
{
    ll ans = 1;
    while(b)
    {
        if(b&1)ans = (ans * a)%mod;
        b>>=1;
        a = ((ll)a * a)%mod;
    }
    return (int)ans;
}
bool check(int x,int n)
{
    for(int i = 0;i<n;i++)
    {
        b[i] = quick_pow(a[i],x);
    }
    UFWT(b,n);
    return b[sum]!=0;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        sum = 0;
        memset(b,0,sizeof(b));
        memset(a,0,sizeof(a));
        int x;
        for(int i = 0;i<n;i++)
        {
            scanf("%d",&x);
            sum ^= x;
            a[x]++;
        }
        a[0]++;
        int m = 1<<19;
        FWT(a,m);
        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",n - ans);
    }
}

参考了:http://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round8-H.html

猜你喜欢

转载自blog.csdn.net/qq_25576697/article/details/81623701