化合物 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;
}

小结:这种题,不指望自己考试能切了