暴力就是
O
(
n
3
)
O(n^3)
O(n3)的树形
d
p
dp
dp,设
f
[
u
]
[
i
]
f[u][i]
f[u][i]为
u
u
u为根的子树,异或和为
i
i
i的方案数,那么转移就是
f
[
u
]
[
i
]
=
∑
v
∈
s
o
n
u
(
f
[
v
]
[
i
]
+
∑
j
=
0
m
−
1
f
[
v
]
[
j
]
×
f
[
u
]
[
i
⊕
j
]
)
f[u][i]=\sum_{v\in son_u}(f[v][i]+\sum_{j=0}^{m-1}f[v][j]\times f[u][i\oplus j])
f[u][i]=∑v∈sonu(f[v][i]+∑j=0m−1f[v][j]×f[u][i⊕j])
注意这里的转移可能会有重叠所以要用一个临时数组记下来,后面可以用
F
W
T
FWT
FWT优化
还有想说 h d u hdu hdu简直有毒, C + + C++ C++会 T T T, G + + G++ G++就能 A A A,而且好像还不太能写快读???
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define N 1100
using namespace std;
const int mod=1e9+7;
int t,n,m,val[N],a[N],b[N];
int f[N][N],inv2,ans[N];
vector<int> mp[N];
inline void FWT(int F[],int type){
for(int mid=1;mid<m;mid<<=1)
for(int r=mid<<1,j=0;j<m;j+=r)
for(int k=0;k<mid;k++){
int x=F[j+k],y=F[j+mid+k];
F[j+k]=(x+y)%mod,F[j+mid+k]=(x-y+mod)%mod;
if(type==-1) F[j+k]=1LL*inv2*F[j+k]%mod,F[j+mid+k]=1LL*inv2*F[j+mid+k]%mod;
}
}
inline void solve(int a[],int b[]){
FWT(a,1); FWT(b,1);
for(int i=0;i<m;i++) a[i]=1LL*a[i]*b[i]%mod;
FWT(a,-1);
}
void DP(int u,int fa){
f[u][val[u]]=1;
for(int i=0;i<mp[u].size();i++){
int v=mp[u][i]; if(v==fa) continue;
DP(v,u);
for(int j=0;j<m;j++) a[j]=f[u][j];
solve(f[u],f[v]);
for(int j=0;j<m;j++) f[u][j]=(f[u][j]+a[j])%mod;
}
for(int i=0;i<m;i++) ans[i]=(ans[i]+f[u][i])%mod;
}
int main(){
scanf("%d",&t); inv2=(mod+1)>>1; int x,y;
while(t--){
scanf("%d%d",&n,&m);
memset(f,0,sizeof f); memset(ans,0,sizeof ans);
for(int i=1;i<=n;i++) scanf("%d",&val[i]),mp[i].clear();
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
mp[x].push_back(y); mp[y].push_back(x);
}
DP(1,0);
for(int i=0;i<m-1;i++) printf("%d ",ans[i]); printf("%d\n",ans[m-1]);
}
return 0;
}