zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校第二场E-Exclusive OR(FWT)

    CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/107929968
    题目大意:给你n个数,(a_i(0leq a_i<2^{18})),你现在需要选出其中(1,2,3,....n)个数,使得其(a_1igoplus a_2igoplus ...igoplus a_i)的值最大。(1leq nleq 2 imes 10^5)

    输入
    4
    1 4 5 7

    输出
    7 6 7 7

    说明
    ({i = 1 : 7 = 7})
    (i = 2 : 7oplus 1 = 6)
    (i = 3 : 7oplus 1 oplus 1 = 7)
    (i = 4 : 7oplus 1 oplus 4 oplus 5 = 7)

    对于只取一个数的情况我们很容易知道它是个什么状态,那么取两个数的情况一定是再取一个的基础上再取一个的,取三个数的情况是在取两个数的情况下再取一个的...依此类推,那么我们就大概可以得到第(i)个状态是由第(i-1,1)两个转移过来的。

    那么我们用(f_1[x])表示只取一个数的时候(x)是否存在,那么我们对于第(i)个数判断(x)是否存在的时候就是去看看是否有(f_{i-1},f_1)的某两位数相异或等于(x)。那么很明显,我们不能直接枚举,那么做个式子过来就是(f_i[x]=sum_{yotimes z=x}f_{i-1}[y]f_1[z])那么我们就可以发现这是个异或卷积。。。我们每次取的时候卷一下就好了,但取的次数有(n)次,那么如果每一次都卷的话,复杂度就是(nwlog(w))(wleq2^{18})。。然后就会发现直接爆炸!

    所以我们必须要优化时间,实际上对于(i>19)的情况我们可以直接计算,并不需要进行卷积,首先对于(forall iin N^+,ans_{}geq ans_{i-2}),因为只需要再(a_i)的基础上任意取一个数两次就可以满足了,如果(i>19)后有(ans_{i}>ans_{i-2})那么也就是说必须要(i-1)个数才能满秩,而这里的(i-1)至少为19,而题目的数据只有(18),所以矛盾了,即(ans_{i}=ans_{i-2})

    那么我们只需要对前(19)个数进行卷积就OK了。

    以下是AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int mac=3e5+10;
    const int mod=998244353;
    
    namespace FWT{
        const int MOD=998244353;
        inline int FAdd(const int &a,const int &b){return a+b>=MOD? a+b-MOD:a+b;}
        inline int FSub(const int &a,const int &b){return a-b<0? a-b+MOD:a-b;}
        inline int FMul(const int &a,const int &b){return 1ll*a*b%MOD;}
        inline int FPow(int a,int b){int ret=1;while(b){if(b&1)ret=FMul(ret,a);a=FMul(a,a);b>>=1;}return ret;}
        const int INV2=FPow(2,MOD-2);
        void FWTOR(int *ary,const int &len,const int &typ){
            for(int L=2,T=1;L<=len;L<<=1,T<<=1)
                for(int i=0;i<len;i+=L)
                    for(int j=i;j<i+T;j++)
                        if(typ==1) ary[j+T]=FAdd(ary[j+T],ary[j]);
                        else ary[j+T]=FSub(ary[j+T],ary[j]);
        }
        void FWTAND(int *ary,const int &len,const int &typ){
            for(int L=2,T=1;L<=len;L<<=1,T<<=1)
                for(int i=0;i<len;i+=L)
                    for(int j=i;j<i+T;j++)
                        if(typ==1) ary[j]=FAdd(ary[j],ary[j+T]);
                        else ary[j]=FSub(ary[j],ary[j+T]);
        }
        void FWTXOR(int *ary,const int &len,const int &typ){
            for(int L=2,T=1;L<=len;L<<=1,T<<=1)
                for(int i=0;i<len;i+=L)
                    for(int j=i;j<i+T;j++){
                        int Aj=ary[j];
                        ary[j]=FAdd(Aj,ary[j+T]);
                        ary[j+T]=FSub(Aj,ary[j+T]);
                        if(typ==-1)
                            ary[j]=FMul(ary[j],INV2),ary[j+T]=FMul(ary[j+T],INV2);
                    }
        }
    }
    
    int f[22][mac],ans[mac];
    int fcp[mac],f1[mac];
    
    int main(int argc, char const *argv[])
    {
        int n,mx,nw=0;
        scanf ("%d",&n);
        for (int i=1; i<=n; i++){
            int x;
            scanf ("%d",&x);
            ans[1]=max(ans[1],x); fcp[x]=1;
            f1[x]=1; nw=max(x,nw);
        }
        mx=1; 
        while (mx<=nw) mx<<=1;
        int typefront=1,typeback=-1;
        for (int i=2; i<=19; i++){
            for (int j=0; j<=mx; j++) f[1][j]=fcp[j];
            FWT::FWTXOR(f[1],mx,typefront);
            if (i!=2) FWT::FWTXOR(f[i-1],mx,typefront);
            else FWT::FWTXOR(f1,mx,typefront);
            if (i!=2) for (int j=0; j<=mx; j++) f[i][j]=1LL*f[1][j]*f[i-1][j]%mod;
            else for (int j=0; j<=mx; j++) f[i][j]=1LL*f[1][j]*f1[j]%mod;
            FWT::FWTXOR(f[i],mx,typeback);
            for (int j=0; j<=mx; j++)
                if (f[i][j]) ans[i]=j;
        }
        for (int i=20; i<=n; i++) ans[i]=ans[i-2];
        for (int i=1; i<=n; i++) printf("%d ",ans[i]); printf("
    ");
        return 0;
    }
    
  • 相关阅读:
    MySQL在DOS界面对database和table增删改查
    js中获取css样式的两种方式
    js for循环中点击事件中无法获取每一个i值的问题
    ps快捷键
    一个简单的动态页面(我的第一个博客)
    Centos7 搭建 hadoop3.1.1 集群教程
    CSS rem与em的运用
    JS进制转换总结
    使用JS生成字符视频/画
    破解字体加密
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13474701.html
Copyright © 2011-2022 走看看