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

时间:2021-02-10 13:55:29

@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;
}