uoj#310. 【UNR #2】黎明前的巧克力

题目描述
题解

考虑到选出的两个集合的异或值为 0 0 0 ,所以我们可以看做找出集合,其异或值为 0 0 0 ,然后如果这个集合大小是 x x x ,对答案的贡献就是 2 x 2^x 2x

所以我们考虑每个 i i i 对应一个多项式 ( 1 + 2 x a i ) (1+2x^{a_i}) (1+2xai) ,只要我们把多项式乘起来即可

我们考虑 f w t fwt fwt 过程中 i i i 位置上的数对 j j j 位置的贡献是数值乘上 ( − 1 ) p o p c o u n t ( i & j ) (-1)^{popcount(i\And j)} (1)popcount(i&j) ,不难发现每个多项式 f w t fwt fwt 后数值要么是 − 1 -1 1 ,要么是 3 3 3

所以我们可以把这些多项式相加后做 f w t fwt fwt ,然后设这个位置有 x x x − 1 -1 1,那就有 n − x n-x nx 3 3 3 ,解方程即可,然后这一位将变成 ( − 1 ) x 3 n − x (-1)^x3^{n-x} (1)x3nx,之后再做 i f w t ifwt ifwt 即可

最后答案因为不能选出空集所以要减一

代码
#include <bits/stdc++.h>
using namespace std;
const int N=1<<20,P=998244353;
const int U=(P+1)>>1,V=748683265;
int n,a[N],w[N];
void fwt(int *a,int o){
	for (int i=1;i<N;i<<=1)
		for (int j=0;j<N;j+=(i<<1))
			for (int x,y,k=0;k<i;k++){
				x=a[j+k];y=a[i+j+k];
				a[j+k]=(x+y)%P;a[i+j+k]=(x-y+P)%P;
				if (o) a[j+k]=1ll*a[j+k]*U%P,
					a[i+j+k]=1ll*a[i+j+k]*U%P;
			}
}
int main(){
	scanf("%d",&n);w[0]=1;
	for (int i=1;i<N;i++) w[i]=3ll*w[i-1]%P;
	for (int x,i=1;i<=n;i++)
		scanf("%d",&x),a[0]++,a[x]+=2;
	fwt(a,0);for (int x,i=0;i<N;i++)
		x=1ll*(3*n-a[i]+P)*V%P,
		a[i]=1ll*((x&1)?P-1:1)*w[n-x]%P;
	fwt(a,1);cout<<(a[0]+P-1)%P<<endl;return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值