uoj

description

给你\(n\)个数,求从中选出两个交集为空的非空集合异或和相等的方案数模\(998244353\)。

sol

其实也就是选出一个集合满足异或和为\(0\),然后把它分成两半。

利用生成函数那套理论,就是对于每个\(a_i\),构造一个多项式\(b_i\),其中\(b_0=1,b_{a_i}=2\),然后把这\(n\)个\(b\)做集合异或卷积。这样我们就得到了一个优秀的\(O(na_i\log a_i)\)的做法辣(雾)。

我们考虑一下\(b_0=1,b_{a_i}=2\)的这个\(b\)做一次\(FWT\)后会发生什么。

打表发现,\(b_0=1\)会使得每个位置\(+1\),\(b_{a_i}=2\)会使得某些位置\(+2\),某些位置\(-2\)。所以最终变换出来的序列里只有\(3\)和\(-1\)。

我们能不能手动构造一下这若干个\(b\)的积呢?显然是可以的。我们只需要知道每一个位置上\(3\)的个数就行了(因为不是\(3\)就是\(-1\),知道了\(3\)的个数也就确定了\(-1\)的个数)。

对于每个\(a_i\),在\(b_{a_i}\)的地方加个\(1\),然后把这个\(b\)\(FWT\)一下,得到的就是每一个位置上\(3\)的个数减去\(-1\)的个数。

所以就可以方便地构造出乘积然后\(FWT\)回去了。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 1<<20;
const int mod = 998244353;
int n,mx,len=1,a[N],b[N];
int fastpow(int a,int b){
int res=1;
while(b){if(b&1)res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
return res;
}
void fwt(int *P,int opt){
for (int i=1;i<len;i<<=1)
for (int p=i<<1,j=0;j<len;j+=p)
for (int k=0;k<i;++k){
int x=P[j+k],y=P[j+k+i];
P[j+k]=1ll*(x+y)*opt%mod;
P[j+k+i]=1ll*(x-y+mod)*opt%mod;
}
}
int main(){
n=gi();int inv2=(mod+1)/2;
for (int i=1,x;i<=n;++i)
x=gi(),++a[x],mx=max(mx,x);
while (len<=mx) len<<=1;
fwt(a,1);
for (int i=0;i<len;++i){
int x=1ll*(a[i]+n)*inv2%mod;
a[i]=fastpow(3,x);if((n-x)&1)a[i]=mod-a[i];
}
fwt(a,inv2);
printf("%d\n",(a[0]-1+mod)%mod);
return 0;
}

[UOJ310][UNR #2]黎明前的巧克力的更多相关文章

  1. 【uoj#310】[UNR #2]黎明前的巧克力 FWT

    题目描述 给出 $n$ 个数,从中选出两个互不相交的集合,使得第一个集合与第二个集合内的数的异或和相等.求总方案数. 输入 第一行一个正整数 $n$ ,表示巧克力的个数.第二行 $n$ 个整数 $a_ ...

  2. [UOJ UNR#2 黎明前的巧克力]

    来自FallDream的博客,未经允许,请勿转载,谢谢. 传送门 很奇妙的一道题 首先不难发现一个暴力做法,就是f[i]表示异或和为i的答案数,每次FWT上一个F数组,其中F[0]=1,F[ai]=2 ...

  3. [FWT] UOJ #310. 【UNR #2】黎明前的巧克力

    [uoj#310][UNR #2]黎明前的巧克力 FWT - GXZlegend - 博客园 f[i][xor],考虑优化暴力,暴力就是FWT xor一个多项式 整体处理 (以下FWT代表第一步) F ...

  4. uoj310【UNR #2】黎明前的巧克力(FWT)

    uoj310[UNR #2]黎明前的巧克力(FWT) uoj 题解时间 对非零项极少的FWT的优化. 首先有个十分好想的DP: $ f[i][j] $ 表示考虑了前 $ i $ 个且异或和为 $ j ...

  5. 【UOJ#310】【UNR#2】黎明前的巧克力(FWT)

    [UOJ#310][UNR#2]黎明前的巧克力(FWT) 题面 UOJ 题解 把问题转化一下,变成有多少个异或和为\(0\)的集合,然后这个集合任意拆分就是答案,所以对于一个大小为\(s\)的集合,其 ...

  6. 「UNR#2」黎明前的巧克力

    「UNR#2」黎明前的巧克力 解题思路 考虑一个子集 \(S\) 的异或和如果为 \(0\) 那么贡献为 \(2^{|S|}\) ,不难列出生产函数的式子,这里的卷积是异或卷积. \[ [x^0]\p ...

  7. 【UNR #2】黎明前的巧克力 解题报告

    [UNR #2]黎明前的巧克力 首先可以发现,等价于求 xor 和为 \(0\) 的集合个数,每个集合的划分方案数为 \(2^{|S|}\) ,其中 \(|S|\) 为集合的大小 然后可以得到一个朴素 ...

  8. UOJ #310 黎明前的巧克力 FWT dp

    LINK:黎明前的巧克力 我发现 很多难的FWT的题 都和方程有关. 上次那个西行寺无余涅槃 也是各种解方程...(不过这个题至今还未理解. 考虑dp 容易想到f[i][j][k]表示 第一个人得到巧 ...

  9. UOJ310. 【UNR #2】黎明前的巧克力 [FWT]

    UOJ 思路 显然可以转化一下,变成统计异或起来等于0的集合个数,这样一个集合的贡献是\(2^{|S|}\). 考虑朴素的\(dp_{i,j}\)表示前\(i\)个数凑出了\(j\)的方案数,发现这其 ...

随机推荐

  1. 页面title加icon

    把favicon.ico放入根目录下,在head中添加一下代码 <link rel="icon" type="image/x-icon" href=&qu ...

  2. Python之NumPy中线性代数

    参考博客:http://blog.csdn.net/u013930163/article/details/51839983 网站:https://docs.scipy.org/doc/numpy-de ...

  3. HUST 1328 String (字符串前缀子串个数 --- KMP)

    题意 给定一个字符串S,定义子串subS[i] = S[0..i],定义C[i]为S中subS[i]的数量,求sigma(C[i])(0<=i<N). 思路 我们以子串结尾的位置来划分阶段 ...

  4. Python写入CSV文件的问题

    这篇文章主要是前几天我处理数据时遇到的三个问题: Python写入的csv的问题 Python2与Python3处理写入写入空行不同的处理方式 Python与Python3的编码问题 其实上面第3个问 ...

  5. 使用Python自带的库和正则表达式爬取熊猫直播主播观看人气

    主要是体现代码的规范性 from urllib import request import re class Spider(): url = 'https://www.panda.tv/cate/lo ...

  6. SQL SERVER 正则替换

    use pubdbgo IF OBJECT_ID(N'dbo.RegexReplace') IS NOT NULL DROP FUNCTION dbo.RegexReplace GO --开始创建正则 ...

  7. linux FTP 操作

    1.登陆: ftp 172.xxx.xxx.xxx 按提示输入用户名和密码 2.上传: 单个文件:put /路径/文件名 批量: 输入 prom 此命令是关闭交互(否则总是询问你是否要上传) 输入下载 ...

  8. 逐步实现hash算法(基于BKDRhash函数)

    哈希(Hash)算法,即散列函数.它是一种单向密码体制,即它是一个从明文到密文的不可逆的映射,只有加密过程,没有解密过程.同时,哈希函数可以将任意长度的输入经过变化以后得到固定长度的输出.hash算法 ...

  9. New Concept English there (9)

    31 65% Cats never fail to fascinate human beings. They can be friendly and affectionate towards huma ...

  10. Linux下保存文件

    经常需要dump数据,mark一下 #if 0 FILE * fd = NULL; fd = fopen("/mnt/raw.pcm", "ab+"); if ...