題目大意:給出一棵樹,每個點有一個點權,求對於每個
別問我爲什麼隔了這麼久突然跑回來更blog……我只是在填以前剩下的坑而已。。。
(我花了一整個高三去打遊戲,然後花了一整個大一補高三的內容,到了大二,我退學了2333)
FWT
定義:
對於一個長爲
易證
定義
性質1:
證明:容易發現
性質2:
證明:數學歸納法
設該公式對於長度
公式真尼瑪長- - 是我證麻煩了麼- -
這樣我們就可以在
逆運算呢?
……
令
則
完美。
變換時間複雜度
回來看題,令
用Fwt加速運算,時間複雜度
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1100
#define MOD 1000000007
using namespace std;
struct edge{
int to,next;
}table[M<<1];
int head[M],tot;
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
int n,m,d;
void FWT(int a[],int n,int type/*1-FWT,-1-DWT*/)
{
if(n==1) return ;
for(int i=0;i<n>>1;i++)
{
a[i]+=a[i+(n>>1)];
a[i+(n>>1)]=a[i]-(a[i+(n>>1)]<<1);
a[i]%=MOD;(a[i+(n>>1)]+=MOD)%=MOD;
if(type==-1)
{
a[i]=(MOD+1ll>>1)*a[i]%MOD;
a[i+(n>>1)]=(MOD+1ll>>1)*a[i+(n>>1)]%MOD;
}
}
FWT(a,n>>1,type);FWT(a+(n>>1),n>>1,type);
}
struct abcd{
int a[M];
abcd() {}
abcd(bool)
{
memset(a,0,sizeof a);
}
int& operator [] (int x)
{
return a[x];
}
void FWT(int type)
{
::FWT(a,d,type);
}
friend abcd operator + (abcd x,abcd y)
{
abcd z(true);
for(int i=0;i<d;i++)
z[i]=(x[i]+y[i])%MOD;
return z;
}
friend abcd operator * (abcd x,abcd y)
{
abcd z(true);
for(int i=0;i<d;i++)
z[i]=((long long)x[i]*y[i])%MOD;
return z;
}
}f[M],zero,ans;
void Initialize()
{
for(d=1;d<m;d<<=1);
memset(f,0,sizeof f);
memset(&zero,0,sizeof zero);
memset(&ans,0,sizeof ans);
zero[0]=1;zero.FWT(1);
memset(head,0,sizeof head);
tot=1;
}
void Tree_DP(int x,int from)
{
for(int i=head[x];i;i=table[i].next)
if(table[i].to!=from)
{
Tree_DP(table[i].to,x);
f[x]=f[x]*(f[table[i].to]+zero);
}
ans=ans+f[x];
}
int main()
{
int T;
for(cin>>T;T;T--)
{
cin>>n>>m;
Initialize();
for(int i=1,x;i<=n;i++)
{
scanf("%d",&x);
f[i][x]=1;
f[i].FWT(1);
}
for(int i=1,x,y;i<n;i++)
{
scanf("%d%d",&x,&y);
Add(x,y);Add(y,x);
}
Tree_DP(1,0);
ans.FWT(-1);
for(int i=0;i<m;i++)
printf("%d%c",ans[i],i==m-1?'\n':' ');
}
return 0;
}