zoukankan      html  css  js  c++  java
  • 「NowCoder Contest 295」H. Playing games

    还是见的题太少了

    「NowCoder Contest 295」H. Playing games

    题意:选出尽量多的数使得异或和为$ 0$


    $ Solution:$

    问题等价于选出尽量少的数使得异或和为全集

    根据线性基思想可以推得整个集合的异或集合可以被不超过$ bitcount$个数的异或集合表示

    因此答案也不超过$ bitcount$

    对于原集合我们做若干次$ FWT$

    每次把当前异或集合卷上初始集合

    复杂度$ O(n log^2 n)$

    足以通过本题

    但是还不够

    我们发现我们只是想知道$ FWT$数组中某一位上的值

    设$ f’$是数组$ f$的$FWT$数组

    有$ f_S=frac{1}{2^n} sumlimits f'_T(-1)^{|Scap T|}$

    这样我们只需要初始对原数组$ FWT$一次

    期间一直用点值表达式进行计算

    然后单词$ O(n)$验证即可

    时间复杂度:$ O(n log n)$


    $ my code$

    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #define p 998244353
    #define rt register int
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x = 0; char zf = 1; char ch = getchar();
        while (ch != '-' && !isdigit(ch)) ch = getchar();
        if (ch == '-') zf = -1, ch = getchar();
        while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * zf;
    }
    void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
    void writeln(const ll y){write(y);putchar('
    ');}
    int i,j,k,m,n,x,y,z,cnt,invn;
    int ksm(int x,int y){
        int ans=1;
        for(rt i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*x*ans%p;
        return ans;
    }
    void FWT(int n,int *A,int fla){
        for(rt i=1;i<n;i<<=1)
        for(rt j=0;j<n;j+=i<<1)
        for(rt k=0;k<i;k++){
            const int x=A[j+k],y=A[i+j+k];
            A[j+k]=(x+y)%p,A[i+j+k]=(x-y)%p;
        } 
        if(fla==-1)for(rt i=0;i<n;i++)A[i]=1ll*A[i]*invn%p; 
    }
    int a[524299],b[524299];
    int main(){
        n=read();int s=0;
        for(rt i=1;i<=n;i++){
            x=read();s^=x;
            a[x]=1;
        }
        int lim=524288;invn=ksm(lim,p-2);
        a[0]=1;FWT(lim,a,-1);
        for(rt i=0;i<lim;i++)b[i]=1;
        for(rt i=0;i<=20;i++){
            ll ans=0;
            for(rt j=0;j<lim;j++)if(__builtin_popcount(j&s)&1)ans+=b[j];else ans-=b[j];
            if(ans%p){
                cout<<n-i;
                break;
            }
            for(rt j=0;j<lim;j++)b[j]=1ll*a[j]*b[j]%p;
        }
        return 0;
    }
  • 相关阅读:
    Pyinstaller打包多个py文件
    Oracle 数据库基础教程之用户管理
    Navicat连接Oracle报错ORA-28547
    Oracle 激活用户及重置密码
    coding公钥配置教程
    关于联想笔记本小新自动关机解决方法
    PIP镜像像源
    Bugku——Web——web基础$_POST
    Bugku——Web——web基础$_GET
    Bugku——Web——计算器
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/10048324.html
Copyright © 2011-2022 走看看