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