Loading

集合幂级数

位运算卷积

对于长度为\(2^n\)的数列(下标\([0,2^n-1]\))\(A,B\),定义 \(C_i=\sum_{j \bigoplus k=i}A_j\times B_k\),其中 \(\bigoplus\) 是位运算,该操作被称作位运算卷积,记作 \(C=A\bigoplus B\).

因为 \(FFT\) 的思想是将 \(A,B\) 转化为点值表示法,相乘之后再转成多项式,所以我们可以类似地,寻找一个变换 \(FWT(A)\),使得\(FWT(C)=FWT(A)FWT(B)\),这里是点乘,同时我们希望 \(FWT(A)\)是一个线性变换,也就是说,\(FWT(A+B)=FWT(A)+FWT(B),kFWT(A)=FWT(kA)\)

不妨设 \(FWT(A)_i=\sum_{j=0}^{2^n-1}f(i,j)A_j\),也就是第 \(j\) 位对第 \(i\) 位的贡献系数为 \(f(i,j)\)

那也就是说,

\[(\sum_{j}f(i,j)A_j)\times (\sum_{k}f(i,k)B_k)=(\sum_{p}f(i,p)C_p) \]

\[\sum_{j}\sum_{k}f(i,j)f(i,k)A_jB_k=\sum_{p}f(i,p)C_p \]

同时,因为 \(A \bigoplus B=C\)

即 $$C_p=\sum_{j\bigoplus k=i}A_jB_k$$

\[\sum_{p}f(i,p)C_p=\sum_{p}f(i,p)\sum_{j\bigoplus k=i}A_jB_k \]

\[\sum_{j}\sum_{k}f(i,j)f(i,k)A_jB_k=\sum_{p}f(i,p)\sum_{j\bigoplus k=i}A_jB_k \]

\[\sum_{j}\sum_{k}f(i,j)f(i,k)A_jB_k=\sum_{j}\sum_{k}f(i,j\bigoplus k)A_jB_k \]

对比系数,可得 \(f(i,j)f(i,k)=f(i,j\bigoplus k)\)

同时,可以发现我们上述的推导没有用到任何位运算的性质,也就是说,普通的多项式卷积也符合上述条件,即 \(x^jx^k=x^{j+k}\)

不过就算我们现在有了 \(f\) 依然不能快速计算 \(FWT(A)\)

我们不妨给 \(f(i,j)\) 加上更强的限制,让 两个数的 \(f\) 等于他们每个二进制位上两个数的 \(f\) 的乘积。

那我们考虑分治计算 \(FWT(A)\) ,.

\[FWT(A)_i=\sum_{j=0}^{2^{n-1}-1}f(i,j)A_j+\sum_{j=2^{n-1}}^{2^n-1} f(i,j)A_j \]

\[FWT(A)_i=f(c,0)\sum_{j=0}^{2^{n-1}-1}f(i',j')A_j+f(c,1)\sum_{j=2^{n-1}}^{2^n-1} f(i',j')A_j \]

其中 \(c\)\(i\) 的最高位,\(i',j'\)\(i,j\)去掉最高位之后的数。

容易发现按位去做就可以变成一个子问题了(看看代码就会了)。

那么我们求出 \(FWT(C)\) 之后,只需要逆用 \(FWT(C)\),也就是被称为 \(IFWT(C)\) 就好了,和上述过程几乎一模一样,只是 \(f\) 这个矩阵变成了原本的逆矩阵就好了,这也就是说,位运算卷积适用的情况就是 \(f(i,j)f(i,k)=f(i,j\bigoplus k)\),且矩阵 \(f\) 有逆矩阵。

基础位运算卷积

或卷积

\(C = A | B\)

注意到 \(j\)\(i\) 的子集且 \(k\)\(i\) 的子集等价于 \(j|k\)\(i\) 的子集。

也就是说,构造 \(f(a,b)=[a|b=a]\),也就是说矩阵为:

\[\begin{bmatrix} 1 & 0\\ 1 & 1 \end{bmatrix} \]

我们可以直接得出 \(f\) 的逆矩阵:

\[\begin{bmatrix} 1 & 0\\ -1 & 1 \end{bmatrix} \]

与卷积

\(C = A \& B\)

仿照上面构造 \(f(a,b)=[a|b=b]\)

矩阵为:

\[\begin{bmatrix} 1 & 1\\ 0 & 1 \end{bmatrix} \]

逆矩阵:

\[\begin{bmatrix} 1 & -1\\ 0 & 1 \end{bmatrix} \]

异或卷积

需要一点点观察技巧,构造 \(f(a,b)=(-1)^{|a\& b|}\),这是因为 \((-1)^{|i\& j|}(-1)^{|i\& k|}=(-1)^{|i\& j|+|i\& k|}\),注意到如果某一位\([i\& j]=[i\& k]\),没有贡献,也就是说,否则只要 \(i\) 这一位 是 1 就有贡献,因此 等价于 \(-1^{|i\& (j \bigoplus k)|}\)

矩阵为:

\[\begin{bmatrix} 1 & 1\\ 1 & -1 \end{bmatrix} \]

逆矩阵:

\[\begin{bmatrix} 0.5 & 0.5\\ 0.5 & -0.5 \end{bmatrix} \]

\(\text{K}\) 进制卷积

\(FWT(A)\)的部分是类似的,重点还是构造 \(f\).

高维 max 卷积

也就是每一位取 \(max\)

类似地,设 \(f(a,b)=[max(a,b)=a]\),显然是符合要求的。

\(K=4\) 为例:
矩阵:

\[\begin{bmatrix} 1 & 0 & 0 & 0 \\ 1 & 1 & 0 & 0 \\ 1 & 1 & 1 & 0 \\ 1 & 1 & 1 & 1 \end{bmatrix} \]

也就是下三角矩阵。

逆矩阵:

\[\begin{bmatrix} 1 & 0 & 0 & 0 \\ -1 & 1 & 0 & 0 \\ 0 & -1 & 1 & 0 \\ 0 & 0 & -1 & 1 \end{bmatrix} \]

高维 min 卷积

把上面的矩阵改成上三角就好了。

高维异或卷积

需要用点科技,先放放吧。

Examples

CF1119H Triple

solution

对于第 \(i\) 个数组,设集合幂级数 \(F_i(x)=X\times x^{a_i}+Y\times x^{b_i}+Z\times x^{c_i}\)
那么\(Ans=\prod_{i=1}^n F_i\)
其中乘法为异或卷积。
考虑把每个 \(F_i\)\(FWT\) 然后点乘之后再 \(IFWT\)
依次考虑每一位 \(i\),算出 \(\prod_{j=1}^n FWT(F_j)_i=\prod_{j=1}^n (-1)^{|i\& a_j|}+(-1)^{|i\& b_j|}+(-1)^{| i\& c_j|}\)

这样看似乎不可做,但是考虑后面只有 \(2^3\)中不同的情况,我们算出每种情况的个数就可以直接计算了。

但是 \(8\) 种还是有点多,考虑令 \(a_i,b_i,c_i\) 都异或 \(a_i\),最后再异或 \(\bigoplus_{i=1}^n a_i\)

那么现在 \(|i\& a_j|=0\),贡献确定了,就只剩下 \(4\) 种情况了。

\(X+Y+Z,X+Y-Z,X-Y+Z,X-Y-Z\) 的个数分别是 \(A,B,C,D\),考虑找一些等量关系。

首先由:

  • \(A+B+C+D=n\)

然后,我们考虑带入一些 \(X,Y,Z\)的特值。

  • 只考虑\(x^{b_i}\)

那么 $$\sum_{i=1}^nFWT(F_i)=A+B-C-D$$

因为 \(FWT(F+G)=FWT(F)+FWT(G)\),所以 $$\sum_{i=1}^n FWT(F_i)=FWT(\sum_{i=1}^nF_i)$$

  • 只考虑 \(x^{c_i}\)

那么 $$\sum_{i=1}^nFWT(F_i)=A-B+C-D$$

  • 只考虑 \(x^{b_i\bigoplus c_i}\)

那么 $$\sum_{i=1}^nFWT(F_i)=A-B-C+D$$

这样就可以解出来 \(A,B,C,D\) 了。

Bonus

考虑拓展到 任意的 \(k\) 元组。

仿照上面的思路,我们枚举一个子集 \(S\in [1,2^k-1]\),计算只考虑 $$x^{\bigoplus_{u\in S} w_u}$$,那么 \(FWT(F_j)_i=\prod_{u\in S}(-1)^{|i\& w_{j,u}|}\)

那么 \(\sum_j FWT(F_j)_i=\sum_{u=0}^{2^n-1}C_uf_{u,S}\),其中 \(c_u\)\(u\) 这种情况的出现次数, \(f_{u,S}\) 是贡献系数。

容易发现 \(f_{u,S}=(-1)^{|u\& S|}\),因此我们对于每个\(i\),求出一个长度为\(2^k\)的数组\(H\),那么 \(H=FWT(c)\),因此只需要\(IFWT(H)\)就可以啦

CF582E Boolean Function

solution

注意到一共有 \(2^4\) 种不同的 \(A,B,C,D\)的取值,也就是说一共有 \(2^{16}\)种不同的结果,所以建出表达式树,那么每个非叶节点的\(dp\)为儿子的\(dp\)值的位运算卷积。
复杂度\(O(16n2^{16})\)

#include<bits/stdc++.h>
using namespace std;
const int N = 520;
const int mod = 1e9+7;
void FWTor(int *fwt,int n,int opt)
{
	for(int len=2,l=1;len<=n;len<<=1,l<<=1)
	for(int i=0;i<n;i+=len)
	for(int j=i;j<i+l;j++)
	fwt[j+l]=(fwt[j+l]+1ll*fwt[j]*opt%mod+mod)%mod;
}
void FWTand(int *fwt,int n,int opt)
{
	for(int len=2,l=1;len<=n;len<<=1,l<<=1)
	for(int i=0;i<n;i+=len)
	for(int j=i;j<i+l;j++)
	fwt[j]=(fwt[j]+1ll*fwt[j+l]*opt%mod+mod)%mod;
}
int dp[N][(1<<16)+7];
char s[N];
int get(char c)
{
	int res=0,state=0;
	for(int S=0;S<(1<<4);S++)
	{
		if('A'<=c&&c<='D')res=((S>>(c-'A'))&1);
		if('a'<=c&&c<='d')res=1-((S>>(c-'a'))&1);
		state=state|(res<<S);
	}
	return state;
}
int match[N],L[(1<<16)],R[1<<16];
void And(int *A,int *B,int *C)
{
	for(int i=0;i<(1<<16);i++)L[i]=B[i],R[i]=C[i];
	FWTand(L,(1<<16),1);FWTand(R,(1<<16),1);
	for(int i=0;i<(1<<16);i++)L[i]=1ll*L[i]*R[i]%mod;
	FWTand(L,(1<<16),-1);
	for(int i=0;i<(1<<16);i++)A[i]=(A[i]+L[i])%mod;
}
void Or(int *A,int *B,int *C)
{
	for(int i=0;i<(1<<16);i++)L[i]=B[i],R[i]=C[i];
	FWTor(L,(1<<16),1);FWTor(R,(1<<16),1);
	for(int i=0;i<(1<<16);i++)L[i]=1ll*L[i]*R[i]%mod;
	FWTor(L,(1<<16),-1);
	for(int i=0;i<(1<<16);i++)A[i]=(A[i]+L[i])%mod;
}
void solve(int l,int r)
{
	if(l==r)
	{
		if(s[l]=='?')
		{
			for(int c='A';c<='D';c++)
			{
				int state=get(c);
				dp[l][state]=(dp[l][state]+1)%mod;
			}
			for(int c='a';c<='d';c++)
			{
				int state=get(c);
				dp[l][state]=(dp[l][state]+1)%mod;
			}
		}
		else 
		{
			int state=get(s[l]);
			dp[l][state]=(dp[l][state]+1)%mod;
		}
		return;
	}
	solve(l+1,match[l]-1);
	solve(match[r]+1,r-1);
	int x=match[l]+1;
	if(s[x]!='|')And(dp[l],dp[l+1],dp[match[r]+1]);
	if(s[x]!='&') Or(dp[l],dp[l+1],dp[match[r]+1]);
}
int n,m;
int stk[N],top=0;
int A[N],B[N],C[N],D[N],E[N];
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	for(int i=1;i<=n;i++)
	{
		if(s[i]!='('&&s[i]!=')')continue;
		if(s[i]=='(')stk[++top]=i;
		else 
		{
			int x=stk[top--];
			match[x]=i;
			match[i]=x;
		}
	}
	cin>>m;
	for(int i=1;i<=m;i++)
	cin>>A[i]>>B[i]>>C[i]>>D[i]>>E[i];
	solve(1,n);
	int ans=0;
	for(int S=0;S<(1<<16);S++)
	if(dp[1][S])
	{
		bool flag=1;
		for(int i=1;i<=m;i++)
		{
			int res=0;
			res+=(A[i]<<0);
			res+=(B[i]<<1);
			res+=(C[i]<<2);
			res+=(D[i]<<3);
			if((S>>res)%2!=E[i])flag=0;
		}
		if(flag)ans=(ans+dp[1][S])%mod;
	}
	cout<<ans;
	return 0;
}

CF908H New Year and Boolean Bridges

solution

对于用"A"相连的边,他们一定构成了强连通分量,我们先把他们连起来,对于 "X" 的边,他们必须不能再同一个强连通分量。

对于一个强连通分量,最少的边数显然是一个环。

现在我们就是要合并一些连通分量使得缩点之后剩下一条链。

对于两个连通分量,我们可以将他们变成一个强连通分量,或者连成一条链。

如果环的大小分别是\(A,B\),前者代价是 \(A+B\),后者是 \(A+B+1\),因此我们肯定要贪心的把两个小的合并成一个大的。

因为大小为 \(1\) 的连通分量不影响,所以设最终大小\(>1\)的强连通分量个数为 \(C\),代价为 \(n+C-1\)

如果我们设把\(S\)这个点集联通的最小代价是 \(dp[S]\),那么转移就是\(min-\)子集卷积,显然不可做。

但是注意到代价小于等于 \(n\),因此不妨改成 \(dp[E][S]\)表示能否把\(S\)合并成\(E\)个连通分量,转移是子集卷积,但是注意到如果一个集合合法,他的子集都合法,因此可以直接用或卷积,最终第一次合法的\(E\)就是答案

// LUOGU_RID: 107709248
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 48;
const int M = (1<<23)+7;
char s[N][N];
int popcnt[M],lg[M];
int f(int x,int y){return ((x|y)==x)*((popcnt[x^y]&1)?-1:1);}
void FWT(int *fwt,int n)
{
    for(int len=2,l=1;len<=n;len<<=1,l<<=1)
    for(int i=0;i<n;i+=len)
    for(int j=i;j<i+l;j++)
    fwt[j+l]=fwt[j+l]+fwt[j];
}
int fa[N],siz[N];
int mask[N];
int n,tot;
int col[N];
int dem[M];
int calc[M],dp[M];
int Find(int x)
{
    if(x==fa[x])return x;
    return fa[x]=Find(fa[x]);
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s[i]+1);
        for(int j=1;j<i;j++)
        if(s[i][j]=='A')fa[Find(i)]=Find(j);
    }
    for(int i=1;i<=n;i++)siz[Find(i)]++;
    for(int i=1;i<=n;i++)
    if(i==Find(i))
    {
        if(siz[i]==1)continue;
        col[i]=++tot;
    }
    if(tot==0)
    {
        printf("%d\n",n-1);
        return 0;
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<i;j++)
    if(s[i][j]=='X')
    {
        int x=Find(i),y=Find(j);
        if(x==y)
        {
            cout<<"-1";
            return 0;
        }
        if(siz[x]==1||siz[y]==1)continue;
        mask[col[x]]|=(1<<(col[y]-1));
        mask[col[y]]|=(1<<(col[x]-1));
    }
    lg[0]=-1;
    calc[0]=1;
    for(int i=1;i<(1<<tot);i++)
    {
        lg[i]=lg[i>>1]+1;
        popcnt[i]=popcnt[i>>1]+(i&1);
        int t=lg[i&-i]+1;
        if((mask[t]&(i-(i&-i)))==0)calc[i]=calc[i-(i&-i)];
    }
    for(int i=0;i<(1<<tot);i++)dem[i]=f((1<<tot)-1,i),dp[i]=1;
    FWT(calc,(1<<tot));
    for(int E=0;;E++)
    {
        for(int i=0;i<(1<<tot);i++)dp[i]=dp[i]*calc[i];
        int res=0;
        for(int i=0;i<(1<<tot);i++)res=res+dp[i]*dem[i];
        if(res)
        {
            printf("%d\n",n+E);
            return 0;
        }
    }
    return 0;
}

CF838C Future Failure

solution

对于一个字符串,如果\(i\)出现了\(a_i\)次,那么不同的排列方式个数为\(C=\frac{n!}{\prod a_i!}\)

结论1:如果\(2|C\),先手必胜

证明:

若先手可以通过删字符达到一个必败态,显然先手必胜。

否则先手只能选择重排,重排之后如果对手选择删字符,根据上面,必败。

因此后手也会重排,但是因为\(C\)是偶数,最终必定是先手赢。

\(C\) 是奇数,那么先手必须选择删字符。

先手肯定尽量不想让下一步的局面变成 \(2|C\),因此必须保持奇数。

不妨删除一个\(2\)的次数最小的\(a_i\)然后-1,显然这个次数一定不超过\(n\)里面\(2\)的次数,因此删掉之后方案数乘上\(\frac{a}{n}\),显然\(2\)的个数不会增加,因此必定还是奇数。

这也就是说,谁先删完谁赢,即如果\(n\)是偶数就输,奇数就赢。

现在考虑计数。

如果\(n\)是奇数,显然任意的都合法,方案数\(k^{n}\)

根据勒让德定理,\(\binom{a+b}{a}\)\(p\) 的次数为\(p\)进制下\(a+b\)的进位次数,显然也可以拓展到多个数。

因此排列个数是奇数的充要条件是\(a_1 | a_2 |……a_k=a_1+a_2……a_k\)

也就是子集卷积,然后就完了。

#include<bits/stdc++.h>
using namespace std;
const int N = (1<<18)+1;
int n,k,mod;
typedef long long LL;
const int B = 19;
inline int plu(int x,int y){return (x+y>=mod?x+y-mod:x+y);}
inline int dec(int x,int y){return (x-y<0?x-y+mod:x-y);}
int Pow(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;
}
int limit;
int D;
void FWT(int *f)
{
	for(int len=2,l=1;len<=limit;len<<=1,l<<=1)
	for(int i=0;i<limit;i+=len)
	for(int j=i;j<i+l;j++)
	f[j+l]=plu(f[j+l],f[j]); 
}
void IFWT(int *f)
{
	for(int len=2,l=1;len<=limit;len<<=1,l<<=1)
	for(int i=0;i<limit;i+=len)
	for(int j=i;j<i+l;j++)
	f[j+l]=dec(f[j+l],f[j]); 
} 
int dp[B][(1<<B)],f[B][(1<<B)];
int popcnt[N];
int ifac[N],fac[N];
void put(int *f)
{
	for(int i=0;i<limit;i++)
	cout<<f[i]<<' ';
	cout<<endl;
}
int main()
{
	cin>>n>>k>>mod;
	if(n%2==1)
	{
		cout<<Pow(k,n);
		return 0;
	}
	ifac[1]=1;
	fac[0]=1;
	limit=(1<<18);
	for(int i=1;i<limit;i++)
	popcnt[i]=popcnt[i>>1]+(i&1);
	int D=popcnt[n];
	for(int i=2;i<limit;i++)
	ifac[i]=1ll*ifac[mod%i]*(mod-mod/i)%mod;
	ifac[0]=1;
	for(int i=1;i<limit;i++)
	ifac[i]=1ll*ifac[i-1]*ifac[i]%mod;
	for(int i=1;i<limit;i++)
	fac[i]=1ll*fac[i-1]*i%mod;
	for(int i=0;i<limit;i++)
	f[popcnt[i]][i]=ifac[i],dp[0][i]=1;
	for(int i=0;i<=D;i++)
	FWT(f[i]);
	int u=k;
	while(k)
	{
		if(k&1) 
		{

			for(int i=D;i>=0;i--)
			for(int j=0;j<i;j++)
			for(int k=0;k<limit;k++)
			dp[i][k]=plu(dp[i][k],1ll*dp[j][k]*f[i-j][k]%mod);			
		}
		for(int i=D;i>=0;i--)
		for(int j=0;j<i;j++)
		for(int k=0;k<limit;k++)
		f[i][k]=plu(f[i][k],1ll*f[j][k]*f[i-j][k]%mod);
		k>>=1;
	}
	IFWT(dp[popcnt[n]]);
	int ans=dec(Pow(u,n),1ll*dp[popcnt[n]][n]*fac[n]%mod);
	cout<<ans;
	return 0;
}
 

CF1326F2 Wise Men (Hard Version)

solution

因为同时要求有边和无边,比较难处理,所以不妨我们先不处理无边的限制,也就是说对于1,我们还是限制两点有边,对于0,我们不做限制。

可以发现这时候的0既可以当做0又可以当做1,因此现在求的答案是原答案的高维后缀和,差分回去就好了。

那么现在序列可以被划分成若干连续段,每段都是1。

对应到原图上,就是原图被划分成若干条链,我们把单点也算作链。

首先求出\(g_S\)表示选出一条覆盖的点集为\(S\)的链的方案数。

我们把它存到\(G_{|S|,S}\)中,就类似于子集卷积中的占位集合幂级数。

因为考虑到最终01段的划分是无序的,所以实际上的状态数是18的分拆数是很小的。

我们直接爆搜分拆数就好了。

对于方案数,我们只需要求出最终点集的并集为\(S\)的方案数\(f_S\)就好了。

为什么?乍一看我们这样做无法保证点集之间互不相交,但是事实上所有幂级数的大小之和就是\(n\),那我们既然覆盖的点集也是\(n\),自然就不交了。

因此我们只需要做或卷积就行了。

先对每一个\(G_i\)做FWTor,然后\(dfs\)的时候直接点值相乘。

最后我们应该要再做IFWTor,但是我们只需要求\(2^n-1\)项的值,所以根据IFWT的本质是高维差分,直接容斥计算就好了。

#include<bits/stdc++.h>
using namespace std;
const int N = 19;
const int M = (1<<18)+7;
typedef long long LL;
int n;
void FWTor(LL *fwt,int lim)
{
	for(int len=2,l=1;len<=lim;len<<=1,l<<=1)
	for(int i=0;i<lim;i+=len)
	for(int j=i;j<i+l;j++)
	fwt[j+l]+=fwt[j];
} 
void IFWT(LL *fwt,int lim)
{
	for(int len=2,l=1;len<=lim;len<<=1,l<<=1)
	for(int i=0;i<lim;i+=len)
	for(int j=i;j<i+l;j++)
	fwt[j]-=fwt[j+l];
}
LL dp[N][M];
LL g[N][M];
char mp[N][N];
inline int bit(int x){return 1ll<<(x-1);} 
inline int get(int x,int v){return (x>>(v-1))&1;}
int popcnt[M];
int U;
LL f[N][M];
map<vector<int> ,LL> DP;
vector<int> perm;
void GenerSet(int x,int a,int k)
{
	if(x==n+1)
	{
		LL ans=0;
		for(int S=0;S<=U;S++)
		{
			int c=popcnt[U^S];
			if(c&1) ans-=f[k][S];
			else ans+=f[k][S];
		}
		DP[perm]=ans;
		return;
	}
	for(int i=a;i+x<=n+1;i++)
	{
		perm.push_back(i);
		for(int S=0;S<=U;S++)
		f[k+1][S]=g[i][S]*f[k][S]; 
		GenerSet(x+i,i,k+1);
		perm.pop_back();
	}
}
LL ret[M];
int main()
{
	cin>>n;
	U=(1<<n)-1;
	for(int i=1;i<=n;i++)
	scanf("%s",mp[i]+1);
	for(int i=1;i<=n;i++)
	dp[i][bit(i)]=1;
	for(int i=1;i<=U;i++)popcnt[i]=popcnt[i>>1]+(i&1);
	for(int S=1;S<=U;S++)
	for(int i=1;i<=n;i++)
	if(dp[i][S])
	{
		for(int j=1;j<=n;j++)
		if(get(S,j)==0&&mp[i][j]=='1')
		dp[j][S|bit(j)]+=dp[i][S];
		g[popcnt[S]][S]+=dp[i][S];
	}
	for(int i=1;i<=n;i++)FWTor(g[i],U+1);
	for(int i=0;i<=U;i++)f[0][i]=1;
	GenerSet(1,1,0); 
	for(int S=0;S<(1<<(n-1));S++)
	{
		perm.clear();
		int pre=-1;
		for(int i=0;i<n-1;i++)
		if(((S>>i)&1)==0) 
		{
			perm.push_back(i-pre);
			pre=i;
		}
		perm.push_back(n-1-pre);
		sort(perm.begin(),perm.end());
		ret[S]=DP[perm];
	}
	IFWT(ret,(1<<(n-1)));
	for(int i=0;i<(1<<(n-1));i++)
	printf("%lld ",ret[i]);
	return 0;
}
posted @ 2023-04-08 16:41  Larunatrecy  阅读(52)  评论(0)    收藏  举报