Problem Description
给定一棵n个节点带点权的树,第i行输出异或和为i的子树数量
Solution
终于写了一发FWT,走在时代后头的娃儿
n^2dp比较显然,我们用FWT加速异或卷积就可以nlogn了。写起来还行,比FFT简单多了
网上很多写法好像都是可能T掉菊花图的,不管了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int MOD=1000000007;
const int ny2=500000004;
const int N=2055;
struct edge {int y,next;} e[N*2];
int f[N][N],ans[N],ls[N];
int n,m,edCnt;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}
void FWT(int *a,int n,int f) {
for (int i=1;i<n;i<<=1) {
for (int j=0;j<n;j+=(i<<1)) {
for (int k=0;k<i;++k) {
int u=a[j+k],v=a[j+k+i];
a[j+k]=(u+v)%MOD,a[j+k+i]=(u+MOD-v)%MOD;
if (f==-1) {
a[j+k]=1LL*a[j+k]*ny2%MOD;
a[j+k+i]=1LL*a[j+k+i]*ny2%MOD;
}
}
}
}
}
void dfs(int x,int fa) {
FWT(f[x],m,1);
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y==fa) continue;
dfs(e[i].y,x);
rep(j,0,m-1) f[x][j]=1LL*f[x][j]*f[e[i].y][j]%MOD;
}
FWT(f[x],m,-1);
f[x][0]++;
FWT(f[x],m,1);
}
int main(void) {
freopen("data.in","r",stdin);
for (int T=read();T--;) {
fill(ls,0); fill(ans,0); fill(f,0);
edCnt=0;
n=read(),m=read();
rep(i,1,n) f[i][read()]++;
rep(i,2,n) add_edge(read(),read());
dfs(1,0);
rep(i,1,n) FWT(f[i],m,-1);
rep(i,1,n) f[i][0]--;
rep(i,1,n) rep(j,0,m-1) {
ans[j]=(ans[j]+f[i][j])%MOD;
}
rep(i,0,m-1) {
if (i==m-1) printf("%d\n", ans[i]);
else printf("%d ", ans[i]);
}
}
return 0;
}