2019.01.15-jzoj-子序列&&dtoj-4114-sub

题目描述:

他得到了一个长度为 n 的数组 a1,a2,a3,...,an,他想知道 xor 值为 0 的子 序列最长是多少。

标签:线性基,FWT

思路:

我们要找异或值为0的,可以反过来寻找异或值为整个数组异或值的数。我们知道一个序列的线性基为权值位数,即至多为log个。

所以我们可以知道异或值为总异或值的个数的至多有log次,次数不多。

所以我们可以对整个序列做至多log次FWT,求出至少在第几次存在异或值等于总异或值,n-次数即为答案。

以下代码:

#include<bits/stdc++.h>
#define il inline
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=6e5+5;
int n,a[N],t=1,l,mx,sum,v[N],b[N],c[N];
il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;}
il void fwt(int *s,int tp){
    for(int i=1;i<t;i<<=1){
        for(int j=0;j<t;j+=i<<1){
            for(int k=0;k<i;k++){
                int A=s[j+k],B=s[i+j+k];
                s[j+k]=A+B;s[i+j+k]=A-B;
                if(tp==-1)s[j+k]=s[j+k]/2,s[i+j+k]=s[i+j+k]/2;
            }
        }
    }
}
int main()
{
    n=read();for(int i=1;i<=n;i++){int x=read();b[x]=1;mx=max(mx,x);sum^=x;}
    while(t<=mx)t<<=1,l++;
    if(sum==0){printf("%d
",n);return 0;}
    if(b[sum]){printf("%d
",n-1);return 0;}
    fwt(b,1);for(int i=0;i<t;i++)c[i]=b[i];
    for(int k=1;;k++){
        if(k>1){
            for(int i=0;i<t;i++)if(c[i]!=0)c[i]=1;
            fwt(c,1);
        }
        for(int i=0;i<t;i++)c[i]=c[i]*b[i];
        fwt(c,-1);
        if(c[sum]!=0){printf("%d
",n-k-1);return 0;}
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Jessie-/p/10274272.html