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 ak−bk=n
输入格式
The first line of input is an integer T
(
1
≤
T
≤
20
)
(1 ≤ T ≤ 20)
(1≤T≤20) 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}
1≤n≤1018,
3
≤
k
≤
64
3 ≤ k ≤ 64
3≤k≤64.
输出格式
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();
}
};