【NOI题解】【bzoj题解】NOI2008 bzoj1063 道路设计

@ACMLCZH学长出的毒瘤题T3。再也不是“善良”的出题人了。

题意:bzoj

题解:

经典的树形DP题目,屡见不鲜了,然而我还是没有写出来。

这一类的题目有很多,例如这里的C题

主要套路是把对儿子的枚举变成一个类似背包的转移方式,实现降复杂度。

需要注意的是某一个地方的DP值不能直接拿来判断是否有解,例如mod=1时,DP值全为0就没法判断了。

这里比较骚的操作是把mod的倍数变成mod,而0不变,这样就不会漏判。

#include<bits/stdc++.h>
#define F(i,a,b) for(int i=a;i<=(b);++i)
#define eF(i,u) for(int i=h[u];i;i=nxt[i])
#define ll long long
using namespace std;

int n,mod;
ll f[100001][21][3],g[100001][21][3];

int h[100001],nxt[200001],to[200001],tot;
inline void ins(int x,int y){nxt[++tot]=h[x];to[tot]=y;h[x]=tot;}

inline ll M(ll x){return x?(x-1)%mod+1:0;}

void DFS(int u,int fa){
	int cnt=0;
	eF(i,u) if(to[i]!=fa) DFS(to[i],u), ++cnt;
	if(!cnt){
		F(j,0,20) f[u][j][0]=1;
		return;
	}
	F(j,0,20) f[u][j][0]=1;
	eF(i,u) if(to[i]!=fa){
		F(j,0,20){
			g[u][j][0]=M(j?f[u][j][0]*(f[to[i]][j-1][0]+f[to[i]][j-1][1]+f[to[i]][j-1][2]):0);
			g[u][j][1]=M(f[u][j][0]*(f[to[i]][j][0]+f[to[i]][j][1])+(j?f[u][j][1]*(f[to[i]][j-1][0]+f[to[i]][j-1][1]+f[to[i]][j-1][2]):0));
			g[u][j][2]=M(f[u][j][1]*(f[to[i]][j][0]+f[to[i]][j][1])+(j?f[u][j][2]*(f[to[i]][j-1][0]+f[to[i]][j-1][1]+f[to[i]][j-1][2]):0));
			f[u][j][0]=g[u][j][0];
			f[u][j][1]=g[u][j][1];
			f[u][j][2]=g[u][j][2];
		}
	}
}

int main(){
	scanf("%d%d",&n,&mod);
	int x,y; F(i,2,n) scanf("%d%d",&x,&y), ins(x,y), ins(y,x);
	DFS(1,0);
	F(j,0,20)
		if(f[1][j][0]+f[1][j][1]+f[1][j][2]){
			printf("%d\n%lld",j,(f[1][j][0]+f[1][j][1]+f[1][j][2])%mod);
			break;
		}
	return 0;
}
posted @ 2018-03-07 21:13  粉兔  阅读(181)  评论(0编辑  收藏  举报