bzoj4730

Alice 和 Bob 又在玩游戏。

有  n n 个节点, m m 条边( 0mn1 0≤m≤n−1),构成若干棵有根树,每棵树的根节点是该连通块内编号最小的点。

Alice 和 Bob 轮流操作(Alice 先手),每回合选择一个没有被删除的节点  x x,将  x x 及其所有祖先全部删除,不能操作的人输。

需要注意的是,树的形态是在一开始就确定好的,删除节点不会影响剩余节点父亲和儿子的关系。

比如:1-3-2 这样一条链,1 号点是根节点,删除 1 号点之后,3 号点还是 2 号点的父节点。

假设 Alice 和 Bob 都足够聪明,问 Alice 有没有必胜策略。

输入格式

第一行一个正整数  T T,表示该测试点有  T T 组数据;接下来  T T 组数据。

对于每组数据:

输入第一行两个整数  n n m m,分别表示点数和边数(节点从  1 1 开始编号)。

接下来  m m 行,每行两个正整数  a a b b,表示节点  a a 和节点  b b 之间有一条边,输入数据中没有重边。

输出格式

输出  T T 行,每行输出 Alice 先手并且 Alice 和 Bob 都足够聪明的情况下谁获胜。

样例

input
4
2 1
1 2
3 2
1 2
1 3
2 0
3 1
1 2

output
Alice
Alice
Bob
Alice

explanation

输入共 4 组数据;

第一组数据输入是一条链,Alice 可以一次性把所有节点都删掉。

第二组数据,Alice 先手第一步删除 1 号点即可胜利。

限制与约定

对于 10% 10%的数据, m=0 m=0;

对于 20% 20%的数据, 1n20 1≤n≤20;

对于 40% 40%的数据, 1n102 1≤n≤102

对于 60% 60%的数据, 1n103 1≤n≤103

对于 100% 100%的数据, 1T10,1n105,n2×105,0mn1 1≤T≤10,1≤n≤105,∑n≤2×105,0≤m≤n−1,输入数据保证不会形成环,且每棵树的大小 5×104 ≤5×104

时间限制 2s

对于一个子树的根为root,假定x在以root为根的子树中,那么删除x到根的所有节点之后剩下的游戏状态就是son[z](其中z在x到root的路径上),也就是删掉x的后继状态就是son[z]的sg1值的异或和,那么root的sg值就是他的所以子节点的sg1值的mex。(注意区分sg1和sg)

然后我们发现对于每个根节点他的儿子的sg1值都是不断在变化的,对于一个x,他的sg1值为sg1[son[x]],以及sg1[son[root]](其中x不在son[root]为根的子树中),我们用一个trie维护,每个trie维护的就是某个点到以一个特定点为root的sg1值,假如我们对于一个z已经维护了它到x的sg1值,那么它到fa[x]的sg1值就是相当于它的所有sg1值异或上sg1[son[fa[x]]其中son[fa[x]]!=x。如果用trie维护一个点到某个点的sg1值,那么我们就只要异或上一个数就行了,当然还有支持sg1的合并也就是trie的合并。实现中有一些细节需要注意。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 100005;
int f[MAXN], i, n, j, m, k, l, x, y, T;
int first[MAXN], next[MAXN << 1], go[MAXN << 1], t, size[MAXN * 21];
int root[MAXN], s[MAXN * 21][2], nn, d[20], len, cnt[MAXN * 21], ans;
bool vis[MAXN];
inline void add(const int &x, const int &y)
{
	next[++t] = first[x]; first[x] = t; go[t] = y;
}
inline int get()
{
	char c;
	while ((c = getchar()) < 48 || c > 57);
	int res = c - 48;
	while ((c = getchar()) >= 48 && c <= 57)
		res = res * 10 + c - 48;
	return res;
}
inline void rev(int x, int dep, int y)
{
	cnt[x] ^= y;
	if ((y >> (nn - dep - 1)) & 1)
		swap(s[x][0], s[x][1]);
}
inline void putdown(int x, int dep)
{
	if (cnt[x])
	{
		if (s[x][0]) rev(s[x][0], dep + 1, cnt[x]);
		if (s[x][1]) rev(s[x][1], dep + 1, cnt[x]);
		cnt[x] = 0;
	}
}
inline void insert(int x, int sum)
{
	for(int i = 1; i < nn; i ++)
		d[i] = ((sum >> (nn - i - 1)) & 1);
	size[x] ++;
	for(int i = 1; i < nn; i ++)
	{
		if (!s[x][d[i]]) s[x][d[i]] = ++len;
		x = s[x][d[i]];
		size[x] ++;
	}
}
inline int merge(int x, int y, int dep)
{
	if (!x) return y;
	if (!y) return x;
	putdown(y, dep);
	s[x][0] = merge(s[x][0], s[y][0], dep + 1);
	s[x][1] = merge(s[x][1], s[y][1], dep + 1);
	size[x] = size[s[x][0]] + size[s[x][1]];
	if (dep == nn) size[x] = 1;
	return x;
}
inline void dfs(int now, int fa)
{
	vis[now] = 1; f[now] = 0;
	int tot = 0;
	for(int i = first[now]; i; i = next[i])
		if (go[i] != fa) dfs(go[i], now), tot ^= f[go[i]];
	insert(root[now] = ++len, tot);
	for(int i = first[now]; i; i = next[i])
		if (go[i] != fa)
		{
			rev(root[go[i]], 1, tot ^ f[go[i]]);
			root[now] = merge(root[now], root[go[i]], 1);
		}
	int x = root[now];
	for(int i = 1; i < nn; i ++)
	{
		if (!x) break;
		putdown(x, i);
		if (size[s[x][0]] == (1 << (nn - i - 1))) f[now] += (1 << (nn - i - 1)), x = s[x][1];
		else x = s[x][0];
	}
	if (x) f[now] ++;
}
int main()
{
	cin >> T;
	while (T --)
	{
		len = t = 0;
		cin >> n >> m;
		nn = log2(n) + 2;
		memset(vis, 0, sizeof(vis));
		memset(first, 0, sizeof(first));
		memset(s, 0, sizeof(s));
		memset(cnt, 0, sizeof(cnt));
		memset(size, 0, sizeof(size));
		for(i = 1; i <= m; i ++)
		{
			x = get(); y = get();
			add(x, y);
			add(y, x);
		}
		ans = 0;
		for(i = 1; i <= n; i ++)
			if (!vis[i]) dfs(i, 0), ans ^= f[i];
		if (ans) cout << "Alice" << endl;
		else cout << "Bob" << endl;
	}
}


深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值