ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【洛谷6097】【模板】子集卷积

2020-06-19 12:54:41  阅读:260  来源: 互联网

标签:cnt 洛谷 卷积 二进制 FWT cases 6097 define


点此看题面

大致题意: 给定\(a_{0\sim 2^n-1},b_{0\sim 2^n-1}\),求\(c_{0\sim 2^n-1}\)满足\(c_k=\sum_{i|j=k,i\&j=0}a_ib_j\)。

子集卷积

做这个之前,要先了解\(FWT\)。

考虑只要用\(FWT\)做或卷积,就可以轻松满足\(i|j=k\)这一限制,可要同时满足\(i\&j=0\),似乎没法直接搞。

但是,稍加分析我们就会发现,这两个限制放在一起其实会产生一个奇妙的性质。

因为\(i\&j=0\),所以\(i\)和\(j\)不可能在同一位上存在\(1\),而\(i|j=k\),则\(k\)的每一位上的\(1\)应该被恰好分给\(i\)和\(j\)的其中一个。

换言之,\(i\)和\(j\)二进制下\(1\)的个数之和等于\(k\)二进制下\(1\)的个数。

于是,我们定义\(f_{i,j},g_{i,j}\)表示:(\(cnt(j)\)为\(j\)二进制下\(1\)的个数)

\[f_{i,j}=\begin{cases}a_j&i=cnt(j)\\0&i\not=cnt(j)\end{cases},g_{i,j}=\begin{cases}b_j&i=cnt(j)\\0&i\not=cnt(j)\end{cases} \]

然后我们令,\(ans_i=\sum_{j=0}^if_j*g_{i-j}\),则\(c_i=ans_{cnt(i),i}\)。

注意,这里的\(*\)为\(FWT\)的或卷积,因此上式可以看作是卷积套卷积,只不过外层这个卷积\(n\le20\),完全无需优化而已。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 20
#define X 1000000009
using namespace std;
int n,P,a[N+5][1<<N],b[N+5][1<<N],ans[N+5][1<<N],g[1<<N];
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define pc(c) (C==E&&(clear(),0),*C++=c)
		#define D isdigit(c=tc())
		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
	public:
		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc(' ');}
		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
I void FWT(int *s,CI op)//FWT或卷积
{
	RI i,j,k;for(i=1;i^P;i<<=1) for(j=0;j^P;j+=i<<1)
		for(k=0;k^i;++k) s[i+j+k]=(1LL*op*s[j+k]+s[i+j+k])%X;
}
int main()
{
	RI i,j,k;for(F.read(n),P=1<<n,i=0;i^P;++i) g[i]=g[i>>1]+(i&1);//预处理每个数二进制下1的个数
	for(i=0;i^P;++i) F.read(a[g[i]][i]);for(i=0;i^P;++i) F.read(b[g[i]][i]);//读入
	for(i=0;i<=n;++i) FWT(a[i],1),FWT(b[i],1);for(i=0;i^P;++i)//先做DWT
		for(j=0;j<=n;++j) for(k=0;k<=j;++k) ans[j][i]=(1LL*a[k][i]*b[j-k][i]+ans[j][i])%X;//求出ans数组
	for(i=0;i<=n;++i) FWT(ans[i],X-1);for(i=0;i^P;++i) F.write(ans[g[i]][i]);return F.clear(),0;//做IDWT,输出答案
}

标签:cnt,洛谷,卷积,二进制,FWT,cases,6097,define
来源: https://www.cnblogs.com/chenxiaoran666/p/FST.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有