【CCPC】CCPC 2023 Shenzhen Site F

Gift

#图论 #枚举 #基环树

题目描述

Given positive integers n, k, find the number of positive integer solutions to the indeterminate equation a k − b k = n a^k − b^k = n akbk=n

输入格式

The first line of input is an integer T ( 1 ≤ T ≤ 20 ) (1 ≤ T ≤ 20) (1T20) indicating the number of queries. The following T lines,
each contain two integers n, k indicating a single query. It is guaranteed that 1 ≤ n ≤ 1 0 18 1 ≤ n ≤ 10^{18} 1n1018, 3 ≤ k ≤ 64 3 ≤ k ≤ 64 3k64.

输出格式

For each query, output a single line contains a single integer, indicating the answer

样例 #1

样例输入 #1

3
7 3
15 4
31 5

样例输出 #1

1
1
1

解法

首先 n n n个点 n n n条边,显然这是一个基环树,有且存在仅有一个环,因此我们可以使用 t a r j a n tarjan tarjan或者拓扑排序找出这个环。

我们记录每个点的度数,当这个点作为非根节点的时候,它的度数需要 − 1 -1 1,因为我们求的是孩子节点数 ≤ 3 \leq 3 3。 而且题目保证有解,也就是我们只需要处理出度数为 5 5 5的点即可。

考虑每个节点作为根时的贡献,如下图样例所示:

在这里插入图片描述

1. 1. 1. 当根节点的度数 ≥ 5 \geq 5 5时,一定没有贡献

2. 2. 2. 当根节点的度数 = 4 =4 =4时,如果其他节点度数为 5 5 5的个数为 1 1 1时,那么只有这两个点是环上的边才有 1 1 1的贡献。 如果其他节点度数为 5 5 5的个数为 0 0 0时,如果根节点在环上,那么就有 2 2 2的贡献

3. 3. 3.当根节点的度数 ≤ 3 \leq 3 3时,其他节点的度数为 5 5 5的个数为 2 2 2时,那么只有这两个点是环上的边才有 1 1 1的贡献。 如果其他节点度数为 5 5 5的个数为 1 1 1时,如果根节点在环上,那么就有 2 2 2的贡献。如果个数为 0 0 0,那么贡献为环的大小。

代码

const int N = 2e5 + 10;

std::vector<int>e[N];
int num[N], low[N], dcc[N];
int dcc_cnt, n, m, dfn;
std::stack<int>stk;
void tarjan(int u, int fa) {
	low[u] = num[u] = ++dfn;
	stk.push(u);
	for (auto& v : e[u]) {
		if (v == fa) continue;
		if (!num[v]) {
			tarjan(v, u);
			low[u] = std::min(low[u], low[v]);
		}
		else {
			low[u] = std::min(low[u], num[v]);
		}
	}
	if (low[u] == num[u]) {
		++dcc_cnt;
		while (1) {
			int v = stk.top(); stk.pop();
			dcc[v] = dcc_cnt;
			if (u == v) break;
		}
	}
}
int deg[N];
void solve() {
	std::cin >> n;

	std::set<pii>edge;

	for (int i = 1; i <= n; ++i) {
		int u, v;
		std::cin >> u >> v;
		e[u].push_back(v);
		e[v].push_back(u);

		deg[u]++; deg[v]++;
		edge.insert({ u,v });
		edge.insert({ v,u });
	}

	tarjan(1, 1);

	std::vector<std::vector<int>>d(dcc_cnt + 1);
	for (int i = 1; i <= n; ++i) {
		d[dcc[i]].push_back(i);
	}

	std::set<int>c;
	for (int i = 1; i <= dcc_cnt; ++i) {
		if (d[i].size() > 1) {
			for (auto& x : d[i]) {
				c.insert(x);
			}
			break;
		}
	}

	std::vector<int>cnt; 
	for (int i = 1; i <= n; ++i) {
		if(deg[i] == 5) cnt.push_back(i);
	}

	int res = 0;
	for (int i = 1; i <= n; ++i) {
		if (deg[i] == 5) continue;

		else if (deg[i] == 4) {
			if (cnt.size() == 1) {
				if (edge.count({ cnt[0],i }) && c.count(cnt[0]) && c.count(i)) {
					++res;
				}
			}
			else if (cnt.empty()) {
				if (c.count(i)) res += 2;
			}
		}

		else {
			if (cnt.size() == 1) {
				if (c.count(cnt[0])) res += 2;
			}
			else if (cnt.size() == 2) {
				if (edge.count({ cnt[0],cnt[1] }) && c.count(cnt[0]) && c.count(cnt[1])) {
					++res;
				}
			}
			else if (cnt.empty()) {
				res += c.size();
			}
		}
	}

	std::cout << res << "\n";
}


signed main() {
	std::ios::sync_with_stdio(0);
	std::cin.tie(0);
	std::cout.tie(0);

	int t = 1;
	//std::cin >> t;

	while (t--) {
		solve();
	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值