化合物 bzoj-3696
题目大意:给你一棵树,定义两个点i , j之间的A值是(dis[i]-dis[lca(i,j)])xor(dis[j]-dis[lca(i,j)])。对所有的k$\in$[1,n],A值等于k的点对数量。
注释:$1\le n\le 10^5$,$1\le maxdis \le 500$。
想法:说什么异或意义下的母函数,完全不会(具体数学没看完的垃圾蒟蒻)。其实就是个暴力...
我们设dp[pos][i]表示以pos为根,长度为i的链的个数,然后直接转移。每次$H^2$扫,复杂度$O(N\cdot H^2)$,然后... ...就过了。
最后,附上丑陋的代码... ...
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
#define M 101000
using namespace std;
int n,num[M][510],ans[1024];
int head[M],to[M],nxt[M],tot;
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
int dfs(int x)
{
int mx=0; num[x][0]=1;
for(int i=head[x];i;i=nxt[i])
{
int tmp=dfs(to[i])+1; mx=max(mx,tmp);
for(int j=1;j<=tmp;++j)
for(int k=0;k<=mx;++k)
ans[k^j]+=num[x][k]*num[to[i]][j-1];
for(int j=1;j<=tmp;++j) num[x][j]+=num[to[i]][j-1];
}
return mx;
}
int main()
{
scanf("%d",&n); int x;
for(int i=2;i<=n;++i)
{
scanf("%d",&x);
add(x,i);
}
dfs(1); int now;
for(int i=512;i>=0;i--) if(ans[i]){ now=i; break; }
for(int i=0;i<=now;++i) printf("%d\n",ans[i]);
return 0;
}
小结:这种题,不指望自己考试能切了