思路
第一眼看去好像并没有什么思路,于是我们通过手算或者暴力搜索打了一个表,
当 \(n = 2\) 时,当 \(k\) 变化时,答案如表所示
n\ k | 1 | 2 | 3 | 4 |
---|---|---|---|---|
1 | (1, 1) | (2, 2) | (3, 3) | (4, 4) |
2 | (0, 1) | (3, 4) | (15, 16) | (24, 25) |
3 | (0, 1) | (0, 1) | (16, 27) | (108, 125) |
4 | (0, 1) | (0, 1) | (0, 1) | (125, 256) |
于是我们发现在 \(k\) 相同时,\(n\) 增大时的答案有规律,我们发现相邻两项的关系是: 下一项的第二项乘\(\frac{k - n}{k}\) 为上一项的第一项, 然后发现 \(n = k\) 时也是有规律的,两项关系是:第上一项的第二项乘 \(\frac{(k + 1) ^ {n - 1}}{k^{n - 1}}\) 等于这一项的第一项,然后通过归纳总结法得出通项公式:
\[ans = \frac{(k + 1) ^ {n - 1} \times (k - n + 1)}{k ^ n}
\]
由于 \(k ^ n\) 很大,所以高精度
\(C++\) \(AC\) \(Code:\)
#include <bits/stdc++.h>
using namespace std;const int MAXN = 2e3;
const int MAX_PRIME = 210;
int t;
int n, k;
int a[MAX_PRIME], b[MAX_PRIME];
int low[MAX_PRIME];
bitset<MAX_PRIME> not_prime;
vector<int> prime;class number {
public:int val[MAX_PRIME];number() {memset(val, 0, sizeof(val));}number operator*(const number &b) const {number res;for (int i = 0; i < MAX_PRIME; ++i)res.val[i] = val[i] + b.val[i];return res;}
} A, B;class number2 {
public:int val[MAXN];int len;number2() {memset(val, 0, sizeof(val));len = 1;}number2 operator*(const number2 &b) const {number2 res;for (int i = 1; i <= len; ++i) {for (int j = 1; j <= b.len; ++j) {res.val[i + j - 1] += val[i] * b.val[j];}}res.len = len + b.len;for (int i = 1; i <= res.len; ++i) {res.val[i + 1] += res.val[i] / 10;res.val[i] %= 10;}while (res.len > 1 && res.val[res.len] == 0) {res.len--;}return res;}
};number2 change2(int x) {number2 res;if (x == 0) {res.val[1] = 0;res.len = 1;return res;}res.len = 0;while (x > 0) {res.val[++res.len] = x % 10;x /= 10;}return res;
}number2 qpow(number2 base, int x) {number2 res;res.val[1] = 1;while (x > 0) {if (x & 1) {res = res * base;}base = base * base;x >>= 1;}return res;
}void print(number X) {number2 res;res.val[1] = 1;for (int i = 2; i < MAX_PRIME; ++i) {if (X.val[i] > 0) {res = res * qpow(change2(i), X.val[i]);}}for (int i = res.len; i >= 1; --i) {cout << res.val[i];}cout << ' ';
}void init() {for (int i = 2; i < MAX_PRIME; ++i) {if (!not_prime[i]) {prime.push_back(i);low[i] = i;}for (auto pri : prime) {if (pri * i >= MAX_PRIME)break;not_prime[pri * i] = true;low[pri * i] = pri;if (i % pri == 0)break;}}
}number change(int x) {number res;for (auto pri : prime) {while (x % pri == 0) {res.val[pri]++;x /= pri;}}return res;
}number pow_(number base, int x) {number res;for (int i = 0; i < MAX_PRIME; ++i) {res.val[i] = base.val[i] * x;}return res;
}void print_() {print(A);print(B);cout << '\n';
}void solve() {cin >> n >> k;if (n > k) {cout << "0 1\n";return;}number k_ = change(k);number k_plus_1 = change(k + 1);number k_plus_1_jian_n = change(k + 1 - n);A = pow_(k_plus_1, n - 1) * k_plus_1_jian_n;B = pow_(k_, n);for (int i = 2; i < MAX_PRIME; ++i) {int min_val = min(A.val[i], B.val[i]);A.val[i] -= min_val;B.val[i] -= min_val;}print_();
}int main() {
#ifndef DEBUGfreopen("a.in", "r", stdin);freopen("a.out", "w", stdout);
#endifinit();cin >> t;while (t--) {solve();}return 0;
}