CodeForces 1924E Paper Cutting Again

洛谷传送门

CF 传送门

印度出题人玩神玩的吧???

考虑计算每条折线被选的概率。考虑相当于是有一个 \(1 \sim n + m - 2\) 的排列 \(p\),然后一条 \(x = i\) 的直线被选且不是最后一个被选的,当且仅当它在 \(p\) 中排在 \(x = 1 \sim i - 1\)\(y = 1 \sim \left\lfloor\frac{k}{i}\right\rfloor\) 之前。\(y = i\) 则类似。

一个 \(1 \sim N\) 的排列中,\(M\) 个数中一个数在其他 \(M - 1\) 个数前面的概率是 \(\frac{1}{M}\)。于是我们能很轻松地枚举每条 \(x = i\)\(y = i\) 的直线计算答案。总时间复杂度 \(O(n + m)\)

code
// Problem: E. Paper Cutting Again
// Contest: Codeforces - Codeforces Round 921 (Div. 1)
// URL: https://codeforces.com/problemset/problem/1924/E
// Memory Limit: 256 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 2000100;
const int N = 2000000;
const ll mod = 1000000007;

ll inv[maxn], n, m, K;

inline void init() {
	inv[1] = 1;
	for (int i = 2; i <= N; ++i) {
		inv[i] = (mod - mod / i) * inv[mod % i] % mod;
	}
}

void solve() {
	scanf("%lld%lld%lld", &n, &m, &K);
	--K;
	if (n * m <= K) {
		puts("0");
		return;
	}
	ll ans = 1;
	for (int i = 1; i < n; ++i) {
		ll j = min(K / i, m);
		if (j == m) {
			continue;
		}
		ans = (ans + inv[i + j]) % mod;
	}
	for (int i = 1; i < m; ++i) {
		ll j = min(K / i, n);
		if (j == n) {
			continue;
		}
		ans = (ans + inv[i + j]) % mod;
	}
	printf("%lld\n", ans);
}

int main() {
	init();
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}
posted @ 2024-01-28 22:00  zltzlt  阅读(58)  评论(0)    收藏  举报