题解 P6499 【[COCI2016-2017#2] Burza】
偏思维的状压 dp 。
不要被数据范围吓到,当
首先,删掉所有深度大于
注意到 Daniel 第
考虑最坏的情况,就是根节点下面连了
对于其他的情况,每次堵住当前最大的子树,如果这棵子树已经变成一条链,那么转换为之前的情况,否则堵住的点数肯定多于之前的情况。所以只要
现在数据范围已经被大幅缩小,只需要
根据 dfs 序的性质, 每一棵子树可以用 dfs 序上一段区间表示。那么我们预处理出 dfs 序。设
设
当
具体转移方程和细节见代码。
#include<bits/stdc++.h>
using namespace std;
const int N=403;
bool b[N],f[N][525003];
int he[N],to[N*2],ne[N*2],fa[N],g[N],d[N],p[N],id;
void dfs1(int x,int y){//预处理父亲和深度
fa[x]=y,d[x]=d[y]+1;
for(int i=he[x],j;i;i=ne[i])if((j=to[i])!=y)dfs1(j,x);
}
void dfs2(int x,int y,int z){//预处理dfs序
for(int i=he[x],j;i;i=ne[i])if((j=to[i])!=y&&b[j])dfs2(j,x,++id);
g[z]=id,p[z]=d[x];
}
int main(){
int n,k,u,i,j,l,v,t=0;
scanf("%d%d",&n,&k),u=1<<k,d[0]=-1;
if(k>19)return puts("DA"),0;
for(i=1;i<n;++i){
scanf("%d%d",&j,&l);
ne[++t]=he[j],to[t]=l,he[j]=t;
ne[++t]=he[l],to[t]=j,he[l]=t;
}
dfs1(1,0);
for(i=1;i<=n;++i)if(d[j=i]==k)do b[j]=1;while(j=fa[j]);//标记有用点
dfs2(1,0,0),memset(f[id+1],1,u);
for(i=id;i;--i){
if(g[i]>i)memcpy(f[i],f[i+1],u);
for(j=0,l=g[i]+1,v=1<<p[i]-1;j<u;++j)if(!(j&v))f[i][j|v]|=f[l][j];
}
puts(f[1][u-1]?"DA":"NE");
return 0;
}