P3330 [ZJOI2011] 看电影
思路
第一眼看去好像并没有什么思路,于是我们通过手算或者暴力搜索打了一个表,
当 \(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 DEBUG
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif
init();
cin >> t;
while (t--) {
solve();
}
return 0;
}

浙公网安备 33010602011771号