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;
}
posted @ 2025-10-13 21:54  孤独的Bochi  阅读(8)  评论(0)    收藏  举报