zoukankan      html  css  js  c++  java
  • UOJ#310 【UNR #2】黎明前的巧克力 FWT 多项式

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ310.html

    题目传送门 - UOJ#310

    题意

      给定 $n$ 个数 ,请你选出两个不相交的集合(两个集合交换一下也算一种),问有多少种选择方案使得两个集合各自包含的数的异或值 相等。

      不能两个都不选。

      $n,a_ileq 10^6$

    题解

      首先,问题可以转化成:选择两个集合,他们的异或值为 $0$ 。

      我们可以构造幂级数。

      对于 $a_i$ 我们构造: $h_i(x)=x^0+2x^{a_i}$ 。

      表示的意义是不选 $a_i$ 有一种方案,选择 $a_i$ 可以把它随便扔给两个集合,有两种方案。

      于是我们只需要把所有的这些幂级数做一个异或卷积就可以了。这里注意一下我们可以通过把每一个多项式的 FWT 乘起来得到最终式子的 FWT 。

      但是直接 FWT 显然要 TLE 。

      我们考虑观察一下这个东西的特殊性质。

      对于同一个多项式 $f$ ,我们观察到 $f_i$ 只有两个系数不为 $0$ 的:$f_0=1,f_{a_i}=2$

      考虑 FWT 的变换式(注意一下这里的 $f_0$ 和 $f_1$ 的意义略有不同,这里是分别指 $f$ 的左边一半和右边一半):

    $$FWT(f)=(FWT(f_0+f_1),FWT(f_0-f_1))$$

      仔细分析可以发现:$f_0$ 对于任意 $FWT(f)_i$ 的贡献都为 $1$ 。而 $f_{a_i}$ 对任意 $FWT(f)_i$ 的贡献只有 $pm 2$ 两种。

      于是 $FWT(f)_i=-1$ 或 $FWT(f)_i=3$ 。

      得到这个结论可以干什么?我们仍然不能把它暴力乘起来。

      但是我们如果得到了所有式子的 FWT 之和,是不是就可以得到 $-1$ 和 $3$ 的个数了?

      对于 FWT ,我们有 $FWT(f+g)=FWT(f)+FWT(g)$ ,即所有多项式的和的 FWT 等于 所有的多项式的 FWT 之和。

      于是我们可以一次 FWT 得到 对于每一个下标的 ,所有多项式的 FWT 的该下标的值的和。

      于是我们可以对于每一个下标,解出这个下标的 $-1$ 的个数,设为 $x$ ,那么,我们就可以得到我们一开始需要的:乘积 $=(-1)^x3^{n-x}$ 。

      然后再 IFWT 回来。

      由于要除掉都不选的情况,$f_0-1$ 就是答案。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=1<<20,mod=998244353;
    const int inv2=499122177,inv4=748683265;
    int n,m=1<<20,a[N],Pow3[N];
    void FWT(int a[],int n,int flag){
    	for (int d=1;d<n;d<<=1)
    		for (int i=0;i<n;i+=(d<<1))
    			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;
    				if (flag==-1){
    					a[i+j]=1LL*a[i+j]*inv2%mod;
    					a[i+j+d]=1LL*a[i+j+d]*inv2%mod;
    				}
    			}
    }
    int main(){
    	scanf("%d",&n);
    	memset(a,0,sizeof a);
    	for (int i=1,x;i<=n;i++){
    		scanf("%d",&x);
    		a[x]+=2,a[0]++;
    	}
    	FWT(a,m,1);
    	Pow3[0]=1;
    	for (int i=1;i<m;i++)
    		Pow3[i]=1LL*Pow3[i-1]*3%mod;
    	for (int i=0;i<m;i++){
    		int x=(1LL*(3*n-a[i])*inv4%mod+mod)%mod;
    		if (x&1)
    			a[i]=(-Pow3[n-x]+mod)%mod;
    		else
    			a[i]=Pow3[n-x];
    	}
    	FWT(a,m,-1);
    	printf("%d",(a[0]+mod-1)%mod);
    	return 0;
    }
    

      

  • 相关阅读:
    python中selenium+unittest实操
    python+selenium元素定位04——浏览器多窗口处理
    python+selenium元素定位03——自动化常见场景处理
    python+selenium元素定位02——层级定位
    requests.post() 方法的使用
    python+selenium元素定位01——显式、隐式等待
    python+selenium之元素识别二
    IO流常用基类
    STS中导入Jmeter源码遇到的坑
    MySql处理日期时间常用函数
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ310.html
Copyright © 2011-2022 走看看