题意:
有一棵n个点的无根树,节点依次编号为1到n,其中节点i的权值为vi,
定义一棵树的价值为它所有点的权值的异或和。
现在对于每个[0,m)的整数k,请统计有多少T的非空连通子树的价值等于k。
Sample Input
2
4 4
2 0 1 3
1 2
1 3
1 4
4 4
0 1 3 1
1 2
1 3
1 4
Sample Output
3 3 2 3
2 4 2 3
令f[i][j]表示以i为根的子树中异或和为j的联通块个数,v为i儿子
f[i][j]+=f[i][k]*f[v][l] (k^l==j)
发现转移其实可以写成这种形式:
$C_i=\sum_{j^k=i}A_j*B_k$
这和卷积有点类似,不过运算改成了异或
这里就要用到FWT(快速沃尔什变换)
就可以做到nlogn转移
转移完后记得在加上原来的f[i][j],因为你可以不选v
复杂度为$O(n^{2}logn)$
卡常,少取模,不要定义long long变量
这题还可以点分治
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 struct Node 8 { 9 int next,to; 10 }edge[2501]; 11 int num,head[1501],Mod=1e9+7,inv2,tmp[2001],a[1001][2001],ans[2001],n,m; 12 int gi() 13 { 14 char ch=getchar(); 15 int x=0; 16 while (ch<‘0‘||ch>‘9‘) ch=getchar(); 17 while (ch>=‘0‘&&ch<=‘9‘) 18 { 19 x=x*10+ch-‘0‘; 20 ch=getchar(); 21 } 22 return x; 23 } 24 void add(int u,int v) 25 { 26 num++; 27 edge[num].next=head[u]; 28 head[u]=num; 29 edge[num].to=v; 30 } 31 int qpow(int x,int y) 32 { 33 int res=1; 34 while (y) 35 { 36 if (y&1) res=1ll*res*x%Mod; 37 x=1ll*x*x%Mod; 38 y/=2; 39 } 40 return res; 41 } 42 void FWT(int *A,int len) 43 {int i,j,k; 44 for (i=1;i<m;i<<=1) 45 { 46 for (j=0;j<m;j+=(i<<1)) 47 { 48 for (k=0;k<i;k++) 49 { 50 int x=A[j+k],y=A[j+k+i]; 51 A[j+k]=x+y; 52 if (A[j+k]>=Mod) A[j+k]-=Mod; 53 A[j+k+i]=x-y+Mod; 54 if (A[j+k+i]>=Mod) A[j+k+i]-=Mod; 55 } 56 } 57 } 58 } 59 void UFWT(int *A,int len) 60 {int i,j,k; 61 for (i=1;i<m;i<<=1) 62 { 63 for (j=0;j<m;j+=(i<<1)) 64 { 65 for (k=0;k<i;k++) 66 { 67 int x=A[j+k],y=A[j+k+i]; 68 A[j+k]=1ll*(x+y)*inv2%Mod; 69 A[j+k+i]=1ll*(x-y+Mod)*inv2%Mod; 70 } 71 } 72 } 73 } 74 void DP(int x,int y) 75 {int i; 76 for (i=0;i<m;i++) 77 tmp[i]=a[x][i]; 78 FWT(a[x],m); 79 FWT(a[y],m); 80 for (i=0;i<m;i++) 81 a[x][i]=1ll*a[x][i]*a[y][i]%Mod; 82 UFWT(a[x],m); 83 for (i=0;i<m;i++) 84 { 85 a[x][i]=a[x][i]+tmp[i]; 86 if (a[x][i]>=Mod) a[x][i]-=Mod; 87 } 88 } 89 void dfs(int x,int pa) 90 {int i; 91 for (i=head[x];i;i=edge[i].next) 92 { 93 int v=edge[i].to; 94 if (v!=pa) 95 { 96 dfs(v,x); 97 DP(x,v); 98 } 99 } 100 for (i=0;i<m;i++) 101 { 102 ans[i]=ans[i]+a[x][i]; 103 if (ans[i]>=Mod) ans[i]-=Mod; 104 } 105 } 106 int main() 107 {int T,i,x,u,v,j; 108 cin>>T; 109 inv2=qpow(2,Mod-2); 110 while (T--) 111 { 112 memset(head,0,sizeof(head)); 113 num=0; 114 memset(a,0,sizeof(a)); 115 memset(ans,0,sizeof(ans)); 116 scanf("%d%d",&n,&m); 117 for (i=1;i<=n;i++) 118 { 119 x=gi(); 120 a[i][x]=1; 121 } 122 for (i=1;i<=n-1;i++) 123 { 124 u=gi();v=gi(); 125 add(u,v);add(v,u); 126 } 127 dfs(1,0); 128 for (i=0;i<m-1;i++) 129 printf("%d ",ans[i]); 130 printf("%d\n",ans[m-1]); 131 } 132 }
原文地址:https://www.cnblogs.com/Y-E-T-I/p/8430651.html
时间: 2024-11-08 23:58:53