Tree Cutting
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 262144/131072 K (Java/Others)
3 3 2 3 2 4 2 3
分析:dp[i][j]表示以i为根异或值为j的方案数;
在加入i的儿子x的子树方案时,dp[i][j]=dp[i][j]+dp[i][k]*dp[x][t](k^t=j);
其中dp[i][k]*dp[x][t](k^t=j)的复杂度为n²,可以用异或卷积加速到nlogn;
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <climits> #include <cstring> #include <string> #include <set> #include <map> #include <queue> #include <stack> #include <vector> #include <list> #define vi vector<int> #define rep(i,m,n) for(i=m;i<=n;i++) #define rsp(it,s) for(set<int>::iterator it=s.begin();it!=s.end();it++) #define mod 1000000007 #define rev (mod+1)/2 #define inf 0x3f3f3f3f #define pb push_back #define mp make_pair #define fi first #define se second #define ll long long #define pi acos(-1.0) using namespace std; const int maxn=1e3+30; int n,m,k,t,a[maxn],dp[maxn][maxn],tmp[maxn],ans[maxn]; vi e[maxn]; void fwt(int *a,int n) { for(int d=1;d<n;d<<=1) for(int m=d<<1,i=0;i<n;i+=m) for(int j=0;j<d;j++) { int x=a[i+j],y=a[i+j+d]; a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod; } } void ufwt(int *a,int n) { for(int d=1;d<n;d<<=1) for(int m=d<<1,i=0;i<n;i+=m) for(int j=0;j<d;j++) { int x=a[i+j],y=a[i+j+d]; a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod; } } void solve(int *a,int *b,int n) { fwt(a,n); fwt(b,n); for(int i=0;i<n;i++)a[i]=1LL*a[i]*b[i]%mod; ufwt(a,n); } void dfs(int now,int pre) { dp[now][a[now]]=1; for(int x:e[now]) { if(x==pre)continue; dfs(x,now); for(int i=0;i<m;i++) tmp[i]=dp[now][i]; solve(dp[now],dp[x],m); for(int i=0;i<m;i++) dp[now][i]=(dp[now][i]+tmp[i])%mod; } for(int i=0;i<m;i++) ans[i]=(ans[i]+dp[now][i])%mod; } int main() { int i,j; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); rep(i,1,n) { scanf("%d",&a[i]),e[i].clear(); rep(j,0,m-1)dp[i][j]=0; } rep(i,0,m-1)ans[i]=0; rep(i,1,n-1) { scanf("%d%d",&j,&k); e[j].pb(k),e[k].pb(j); } dfs(1,0); rep(i,0,m-1)printf("%d%c",ans[i],i<m-1?' ':' '); } //system ("pause"); return 0; }