@ACMLCZH学长出的毒瘤题T3。再也不是“善良”的出题人了。
题意:bzoj。
题解:
经典的树形DP题目,屡见不鲜了,然而我还是没有写出来。
这一类的题目有很多,例如这里的C题。
主要套路是把对儿子的枚举变成一个类似背包的转移方式,实现降复杂度。
需要注意的是某一个地方的DP值不能直接拿来判断是否有解,例如mod=1时,DP值全为0就没法判断了。
这里比较骚的操作是把mod的倍数变成mod,而0变成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; }