首页 > 代码库 > bzoj3696

bzoj3696

3696: 化合物

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 245  Solved: 131
[Submit][Status][Discuss]

Description

    首长NOI惨跪,于是去念文化课了。现在,他面对一道化学题。
    这题的来源是因为在一个奇怪的学校两个化竞党在玩一个奇怪的博弈论游戏。这个游戏很蛋疼,我相信你们也没有兴趣听。
    由于这个游戏涉及博弈论,因此化竞的同学就要求首长求一个类似SG函数的值。
    他们手中有一种非常神奇的化合物,它的分子由N个原子组成(不要在意一个原子可能和及其多个原子成键这个细节)。这个分子构成一个树结构,1号分子为根。    若两个原子i、j到它们的最近公共祖先的距离分别是Li和Lj,定义它们的Aij值为:
Aij=Li  xor Lj
题目要求对于每一个k(k∈N),求出两两A值为k的原子对个数。

Input

  第一行一个整数N。
  接下来N-1行,每行一个整数p,第新亍的整数表示第i个原子的父亲为p。

Output

从K=0开始,第k+1行输出两两A值为K的原子对个数,输出到第一个不为零的数为止。

Sample Input

3
1
1

Sample Output

1
2

HINT

 

【数据规模与约定】

用h表示树结构分子的最大深度。

 N<=10^5,H<=500

 

Source

想了半天,怎么感觉只能做到O(n*H^2) 结果一看题解,居然能跑过去。。。 O(跑得快)

技术分享
#include<bits/stdc++.h>
using namespace std;
#define N 100010
struct edge
{
    int nxt,to;
}e[N<<1];
int n,cnt=1;
int head[N],ans[N],deep[N];
int dp[N][510];
void link(int u,int v)
{
    e[++cnt].nxt=head[u];
    head[u]=cnt;
    e[cnt].to=v;
}
void dfs(int u)
{
    dp[u][0]=1;
    for(int i=head[u];i;i=e[i].nxt)
    {        
        dfs(e[i].to);
        deep[u]=max(deep[u],deep[e[i].to]+1);
        for(int j=0;j<=deep[u];++j)
            for(int k=0;k<=deep[e[i].to];++k)
                ans[j^(k+1)]+=dp[u][j]*dp[e[i].to][k];
        for(int j=0;j<=deep[e[i].to];++j) dp[u][j+1]+=dp[e[i].to][j];
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;++i)
    {
        int u; scanf("%d",&u);
        link(u,i);
    }
    dfs(1);
    int mx=522;
    for(;mx;--mx) if(ans[mx]) break; 
    for(int i=0;i<=mx;++i) printf("%d\n",ans[i]);
    return 0;
}
View Code

 

bzoj3696