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. 深入浅出-Binding的源与路径

    1.把控件作为Binding源与Binding标记扩展<TextBox x:Name="textBox1" Text="{Binding Path=Value, E ...

  2. Linux命令详解-cp

    cp 命令用来复制文件或者目录,是Linux系统中最常用的命令之一.一般情况下,shell会设置一个别名,在命令行下复制文件时,如果目标文件已经存在, 就会询问是否覆盖,不管你是否使用-i参数.但是如 ...

  3. 【原创】移动端获取用户公网ip,获取用户ip

    有时候某些api需要获取用户的ip , 特此分享一下获取用户公网ip的方法 纯js <script src="http://pv.sohu.com/cityjson?ie=utf-8& ...

  4. java开发中beancopy比较

    在java应用开发过程中不可避免的会使用到对象copy属性赋值. 1.常用的beancopy工具 组织(包) 工具类 基本原理 其他 apache PropertyUtils java反射     B ...

  5. 对一致性Hash算法,Java代码实现的深入研究(转)

    转载:http://www.cnblogs.com/xrq730/p/5186728.html 一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读 ...

  6. [sqlite] 判断表、视图是否存在及常用C#操作语句

    1,判断表是否存在: SELECT name, sql FROM sqlite_master WHERE type="table" AND name = "Dom&quo ...

  7. zoj 2976 Light Bulbs(暴力枚举)

    Light Bulbs Time Limit: 2 Seconds      Memory Limit: 65536 KB Wildleopard had fallen in love with hi ...

  8. git重要命令

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  9. 说说C++多重继承

    尽管大多数应用程序都使用单个基类的公用继承,但有些时候单继承是不够用的,因为可能无法为问题域建模或对模型带来不必要的复杂性.在这种情况下,多重继承可以更直接地为应用程序建模. 一.基本概念 多重继承是 ...

  10. Shell学习笔记——算数运算与条件测试

    算数运算 1. 使用let命令 #!/sbin/bash var1=2 var2=3 let sum=var1+var2 echo $sum 使用let命令式,变量前不需要加$号 只用于整数运算,不适 ...