1. 程式人生 > >【BZOJ3696】化合物 樹形DP+暴力

【BZOJ3696】化合物 樹形DP+暴力

getchar getc put bzoj ++ 它的 函數 sample name

【BZOJ3696】化合物

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

題解:第一直覺是某種樹形DP,但是想不出來,看到H很小,感覺暴力可過,發現正解真的是暴力~

對於每一層,我們用f[i]表示當前子樹中深度為i的點的個數,然後我們用下一層的f‘[j]和當前的f[i]來暴力更新答案ans[i^j],然後用f‘[j]來更新f[i]就行了。

註意要輸出到第一個為0的數,而不是輸出所有不為0的數。

隨手寫了一發rank1了什麽鬼~可能因為數組開的比較小吧?

技術分享

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=100010;
int n,mx,cnt;
int fa[maxn],dep[maxn],md[maxn],f[520][520],to[maxn],head[maxn],next[maxn],ans[520];
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
void dfs(int x)
{
	md[x]=dep[x],f[dep[x]][dep[x]]=1;
	int i,j,k;
	for(i=head[x];i!=-1;i=next[i])
	{
		dep[to[i]]=dep[x]+1,dfs(to[i]);
		for(j=dep[x];j<=md[x];j++)
			for(k=dep[x];k<=md[to[i]];k++)
				ans[(j-dep[x])^(k-dep[x])]+=f[dep[x]][j]*f[dep[x]+1][k];
		for(j=dep[x];j<=md[to[i]];j++)
			f[dep[x]][j]+=f[dep[x]+1][j],f[dep[x]+1][j]=0;
		md[x]=max(md[x],md[to[i]]);
	}
}
int main()
{
	n=rd();
	int i;
	memset(head,-1,sizeof(head));
	for(i=2;i<=n;i++)	fa[i]=rd(),add(fa[i],i);
	dep[1]=2,dfs(1);
	for(i=0;i<512;i++)
	{
		if(!ans[i])	return 0;
		printf("%d\n",ans[i]);
	}
}

【BZOJ3696】化合物 樹形DP+暴力