zoukankan      html  css  js  c++  java
  • UOJ #310「UNR #2」黎明前的巧克力

    神仙题啊...

    UOJ #310


    题意

    将原集合划分成$ A,B,C$三部分,要求满足$ A,B$不全为空且$ A$的异或和等于$ B$的异或和

    求方案数

    集合大小 $nleq 10^6$ 值域$val leq 10^6$


    题解

    如果要满足$ A,B$的异或和相同,必然有$ A cup B$中所有元素异或和为$ 0$

    如果存在这样一个集合$ A cup B$,这之中的每个元素可以在集合$ A$中也可以在集合$ B$中

    即对答案产生$ 2^{|A|+|B|}$的贡献

    设每个元素$ a_i$的多项式为$ 2x^{a_i}+1$

    则答案相当于所有多项式的异或卷积结果的常数项的值减一(减去A,B全为空的情况)

    用$ FWT$优化这个卷积,复杂度是$ O(n·val·log val)$

    并得不了什么分

    打表发现这类多项式的$ FWT$结果只有$ -1$和$ 3$两种数

    $ FWT$有一个性质是$ FWT$的和等于和的$ FWT$

    因此我们先对所有多项式求和,再做一次$ FWT$

    这时候的$ FWT$结果可以被$ (-1)x+3(n-x)$表示

    这样可以求出原先这个位置中$ -1$和$ 3$的数量

    就能求出原先数组的$ FWT$之后的对应位乘积的值了

    得到$ FWT$数组后$ O(n)$计算答案即可

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


    代码

    有过一些恶意卡常

    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #define p 998244353
    #define file(x)freopen(x".in","r",stdin);freopen(x".out","w",stdout)
    #define rt register int
    #define ll long long
    #include<sys/mman.h>
    using namespace std;
    struct ano{
        char*s;
        ano():s((char*)mmap(0,1<<24,1,2,0,0)){}
        operator int(){
            int x=0;
            while(*s<48)++s;
            while(*s>32)
                x=x*10+*s++-48;
            return x;
        }
    }buf;
    int k,m,n,x,y,z,cnt,ans,invn;
    int ksm(int x,int y=p-2){
        int ans=1;
        for(rt i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*ans*x%p;
        return ans;
    }
    int A[1048577];
    int mi[1000010],fla[1048576];
    int main(){
        n=buf;int lim=1,mc=0;
        for(rt i=1;i<=n;i++)x=buf,A[0]++,A[x]+=2,mc=max(mc,x);
        while(lim<=mc)lim<<=1;
        mi[0]=1;for(rt i=1;i<=n;i++)mi[i]=1ll*mi[i-1]*3%p;
        for(rt i=1;i<lim;i<<=1)
        for(rt j=0;j<lim;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;A[i+j+k]=x-y;
        } 
        int inv4=ksm(4);
        for(rt i=0;i<lim;i++){
            x=(3ll*n-A[i])*inv4%p;
            (ans+=mi[n-x]*((x&1)?-1:1))%=p;
        }
        ans=1ll*ans*ksm(lim,p-2)%p;
        cout<<(ans+p-1)%p;
        return 0;
    }
  • 相关阅读:
    湘潭大学 Hurry Up 三分,求凹函数的最小值问题
    hdu 1166 线段树 单点修改 + 询问区间求和 (线段树模板)
    hdu 1166 树状数组(模板) 更改点值+求区间和
    getline
    poj 1873 The Fortified Forest 凸包+位运算枚举 world final 水题
    C# 代码操作XML(增、删、改)
    C# Socket服务端与客户端通信(包含大文件的断点传输)
    MD5 十六进制加密
    C# 面向对象——多态
    C# 面向对象——继承
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/10281187.html
Copyright © 2011-2022 走看看