P6499 [COCI2016-2017#2] Burza 题解

Luogu

Description.

Alice Bob 打隔膜,有一棵 \(n\) 个点的树,最初棋子在 \(1\) 节点。
Alice 删掉一个节点,然后 Bob 移动棋子到一个没到过的地方。
Alice 不知道 Bob 的每次操作
问 Alice 有无必胜策略

\(n\le 400\)

Solution.

首先发现 \(k\) 增加时无解情况要求的叶子增加叶子深度也增加。
构造一个无解情况,就需要 \(k\) 条深度为 \(k\) 的链,点数是 \(k^2\) 级别的。
所以如果 \(k^2\ge n\),那肯定有解了。
所以 \(k\) 的范围变成了 \(20\)

每次贪心策略肯定是第 \(i\) 轮删掉一个深度为 \(i\) 的点(根为 \(0\)),这样肯定最优。
因为 Bob 操作不确定,所以我们肯定要把所有深度为 \(K\) 的点删完。
然后可以考虑 dfn dp,就把 dfn 拉出来,然后直接跑状压 dp。
状压 dp 记录当前选了深度为多少的点,直接转移就行了。

Coding.

点击查看代码
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=405;struct ${int d,w;};vector<$>v[N];
struct edge{int to,nxt;}e[N<<1];int n,K,et,head[N],lim;
int dep[N],lf[N],rg[N],dt;char dp[N][524289],vs[N];
inline void adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;}
inline void dfs(int x,int fa)
{
	vs[x]=1,lf[x]=dt;if((dep[x]=dep[fa]+1)==K) return rg[x]=++dt,void();
	for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa) dfs(e[i].to,x);
	rg[x]=dt;
}
int main()
{
	read(n,K);for(int i=1,x,y;i<n;i++) read(x,y),adde(x,y),adde(y,x);
	if(K*K>=n) return puts("DA"),0;else dep[0]=-1,dfs(1,0),dp[0][0]=1,lim=(1<<K)-1;
	for(int i=1;i<=n;i++) if(vs[i]&&i!=1) v[lf[i]].push_back(($){dep[i]-1,rg[i]});
	//for(int i=0;i<=n;i++) for($ j:v[i]) printf("%d %d : %d\n",i,j.w,j.d);
	for(int i=0;i<dt;i++) for(int j=0;j<=lim;j++) if(dp[i][j])
		for(auto x:v[i]) if(!((j>>x.d)&1)) dp[x.w][j|1<<x.d]=1;
	char rs=0;for(int i=0;i<=lim;i++) rs|=dp[dt][i];
	return puts(rs?"DA":"NE"),0;
}
posted @ 2021-11-10 16:07  Peal_Frog  阅读(105)  评论(0编辑  收藏  举报