voidsolve(){ ll h = read(), w = read(), s = read(); if(h * w <= s){puts("0"); return;} const ll inf = 1e18; ll ans = inf;
// ceil(x / y) auto cdiv = [&](ll x, ll y){return (x - 1) / y + 1;};
// 枚举所有可能的 A = ceil(h / x), 跳跃x进行枚举 ll x = 1; while(x <= h){ ll A = cdiv(h, x); if(s / A) ans = min(ans, cdiv(h, A) + cdiv(w, s / A) - 2); // (A-1) * x < h <= A * x ==> 满足不等式的最大x为 (h-1) / (A-1) if(A == 1) break; x = (h - 1) / (A - 1) + 1; } printf("%lld\n", ans); }
voidsolve(){ int n = read(), m = read(); std::vector<std::vector<int>> adj(n+1, std::vector<int>()); std::vector<int> in(n+1); for(int i = 1; i <= m; ++i){ int x = read(), y = read(); adj[x].push_back(y); ++in[y]; }
int cnt = 0; // 必选点个数 std::vector<bool> removed(n+1); auto kahn1 = [&]() -> void { std::queue<int> q; for(int i = 1; i <= n; ++i){ if(!in[i]) q.push(i); } while(q.size()){ int x = q.front(); q.pop(); removed[x] = 1; ++cnt; for(auto& y : adj[x]) if(!--in[y]) q.push(y); } }; kahn1();
std::vector<bool> vis(n+1);
auto kahn2 = [&](int s) -> int { std::vector<int> rec; // recover std::queue<int> q; q.push(s); int res = 0; while(q.size()){ int x = q.front(); q.pop(); vis[x] = 1; ++res; rec.push_back(x); for(auto& y : adj[x]){ if(removed[y] or y == s) continue; if(!--in[y]) q.push(y); } } for(auto& x : rec) for(auto& y : adj[x]) if(!removed[y] and y != s) ++in[y]; return res; };
int ans = 0; std::vector<int> p(n+2); for(int i = 1; i <= n; ++i) p[i] = i; std::random_shuffle(&p[1], &p[n+1]); // 随机起点枚举顺序 for(int i = 1; i <= n; ++i){ if(!removed[p[i]] and !vis[p[i]]) ans = max(ans, kahn2(p[i])); } printf("%d\n", ans += cnt); }
H. Misread Problem
题意: 求一个石子总数为的石子分配方案, 使得该方案 b 分别变成给定的 k 个石子分配方案的总成本最小.
voidsolve(){ int n = read(), m = read(), k = read(); // s[i][j] : 第 i 个位置在第 k 个分布中的石子数 std::vector<std::vector<ll>> a(n, std::vector<ll>(k)); for(int j = 0; j < k; ++j) for(int i = 0; i < n; ++i) a[i][j] = read(); // 排序后的前缀和 std::vector<std::vector<ll>> ps(n, std::vector<ll>(k+1)); for(int i = 0; i < n; ++i){ std::sort(a[i].begin(), a[i].end()); for(int j = 0; j < k; ++j){ ps[i][j+1] = ps[i][j] + a[i][j]; } } int l = 0, r = k, idx = -1; // 达到最优成本对应的索引 while(l <= r){ int mid = l + r >> 1; ll tot = 0; for(int i = 0; i < n; ++i) tot += a[i][mid]; if(tot <= m) idx = mid, l = mid + 1; else r = mid - 1; } // 按 idx 分配 std::vector<ll> b(n); ll used = 0; if(idx != -1){ for(int i = 0; i < n; ++i) b[i] = a[i][idx], used += b[i]; } // 分配剩余石子 ll rem = m - used; std::vector<std::pair<ll, int>> stones; for(int i = 0; i < n; ++i){ // 当前成本 ll cost = std::upper_bound(a[i].begin(), a[i].end(), b[i]) - a[i].begin(); stones.emplace_back(cost, i); } // 按成本从小到大贪心放置 std::sort(stones.begin(), stones.end()); for(constauto& [cost, i] : stones){ if(!rem) break; // 容量 ll cap = idx == k-1 ? m : a[i][idx+1] - b[i]; ll add = min(rem, cap); b[i] += add; rem -= add; }
// 计算总成本 ll ans = 0; for(int i = 0; i < n; ++i){ auto it = std::upper_bound(a[i].begin(), a[i].end(), b[i]); int p = it - a[i].begin(); // 有 p 个位置的石子数 <= b[i] ans += p * b[i] - ps[i][p]; } printf("%lld\n", ans); }