2025 省选模拟 11

2025 省选模拟 11

神秘联考没有比赛名。

得分

T1 T2 T3 总分 排名
\(0\) \(0\) \(4\) \(4\) \(43/45\)
  • 神秘评测机把我 ZR 上测的 \(22\) 分变成 \(4\) 分了,拿到有分倒一。

题解

T1 抽奖

考虑设 \(f(i)\) 表示 \(i\) 元钱的最大收益,可以简单推出答案为 \(\min(i+\dfrac{x}{f(i)})\)

接下来不难发现这是一个背包问题,并且 \(x\) 很大而体积很小。对于这种题有一个经典的结论:除了性价比最高的物品外剩下物品占用空间不超过 \(w^2\),其中 \(w\) 为最大体积数。也就是说如果 \(i> w^2\),我们的 \(f(i)\) 直接就可以等于 \(f(i-A)+B\) 了,其中 \((A,B)\) 为性价比最高物品。

那么我们接下来分两类考虑即可:

  • \(i\le w^2\) 时,\(ans=i+\dfrac{x}{f(i)}\),即 \(i=-\dfrac1{f(i)}\times x+ans\),显然坐标为 \((-\dfrac1{f(i)},i)\),斜率为 \(x\),要求截距最小,维护下凸壳二分即可。复杂度 \(O(q \log w^2)\)
  • \(i >w^2\) 时,我们枚举 \(i\bmod A\) 的余数 \(r\),那么上式可以写成 \(\min(kA+r+\dfrac{x}{f(r)+kB})\)。由均值不等式可以解出使该式最小的 \(k\),然后我们就可以 \(O(1)\) 计算最小值了。注意这里的 \(r\) 实际上是 \(w^2\) 内最后一个 \(\bmod A\)\(r\) 的数字。复杂度 \(O(qw)\)

所以总复杂度就是 \(O(w^3+qw)\),可以通过。注意 \(\dfrac{1}{f(i)}\) 直接算的话精度绝对会炸,需要用一些手法转成整数。

#include <bits/stdc++.h>
#define int long long
#define ll __int128

using namespace std;

const int Maxn = 2e5 + 5;
const int N = 2e5;
const int Inf = 5e18;

int n, q;
int A, B;
struct node {
	int a, b;
}p[Maxn];
int dp[Maxn], ps[Maxn];

void print(ll x) {
	if(x < 0) {cout << '-', x = -x;}
	if(x > 9) print(x / 10);
	cout << (char)(x % 10 + '0');
}

struct Frac {
	ll x, y;
	Frac make(ll p, ll q) {
		if(q < 0) p = -p, q = -q;
		return {p, q};
	}
	Frac operator + (Frac b) {
		ll p = x * b.y + b.x * y, q = y * b.y;
		return make(p, q);
	}
	Frac operator - (Frac b) {
		ll p = x * b.y - b.x * y, q = y * b.y;
		return make(p, q);
	}
	Frac operator * (Frac b) {
		ll p = x * b.x, q = y * b.y;
		return make(p, q);
	} 
	Frac operator / (Frac b) {
		ll p = x * b.y, q = y * b.x;
		return make(p, q);
	} 
	bool operator < (const Frac &b) const {return x * b.y < b.x * y;}
	bool operator == (const Frac &b) const {return (x == b.x) && (y == b.y);}
	bool operator > (const Frac &b) const {return x * b.y > b.x * y;}
	bool operator <= (const Frac &b) const {return *this < b || *this == b;}
	bool operator >= (const Frac &b) const {return *this > b || *this == b;}
	void put() {
		print(x), cout << '/', print(y);
	}
};

struct Point {
	Frac x, y;
	bool operator < (Point b) {return (y == b.y) ? x < b.x : y < b.y;}
	Point operator - (Point b) {return {x - b.x, y - b.y};}
	Frac operator * (Point b) {return x * b.y - y * b.x;}
	Frac operator ()(int t) {return (Frac){y.x * x.y - x.x * t, x.y};}
}a[Maxn];

vector <Point> con;

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n >> q;
	for(int i = 1; i <= n; i++) {
		cin >> p[i].a >> p[i].b;
	}
	sort(p + 1, p + n + 1, [](node x, node y){return x.b * y.a > x.a * y.b;});
	for(int i = 0; i <= N; i++) dp[i] = -Inf;
	dp[0] = 0;
	for(int i = 1; i <= n; i++) {
		for(int j = p[i].a; j <= N; j++) dp[j] = max(dp[j], dp[j - p[i].a] + p[i].b);
	}
	A = p[1].a, B = p[1].b;
	int tot = 0;
	for(int i = 1; i <= N; i++) if(dp[i] >= 0) a[++tot] = {(Frac){-1, dp[i]}, (Frac){i, 1}};
	sort(a + 1, a + tot + 1);
	for(int i = 1; i <= tot; i++) {
		while(con.size() > 1 && (a[i] - con.back()) * (con.back() - con[con.size() - 2]) >= (Frac){0, 1}) con.pop_back();
		con.push_back(a[i]);
	}
	for(int i = 1; i <= N; i++) {
		ps[i % A] = i;
	}
	for(int T = 1; T <= q; T++) {
		int x; cin >> x;
		int l = 0, r = con.size() - 2, res = con.size() - 1;
		while(l <= r) {
			int mid = (l + r) >> 1;
			Frac num1 = con[mid](x), num2 = con[mid + 1](x);
			if(num1 < num2) res = mid, r = mid - 1;
			else l = mid + 1;
		}
		Frac ans = con[res](x);
		for(int i = 0; i < A; i++) {
			int r = ps[i];
			if(dp[r] < 0) continue;
			ll a = A * B, b = 2 * A * dp[r];
			double delta = 4.0 * A * B * x, k = 1;
			if(delta > 0) {
				k = max(k, (-b + sqrt(delta)) / (2.0 * a));
			}
			k = floor(k);
            ll p = r + k * A, q = dp[r] + k * B;
			Frac num = (Frac){p * q + x, q};
			if(num < ans) ans = num;
		 	p += A, q += B, num = (Frac){p * q + x, q};
			if(num < ans) ans = num;
		}
		ll g = __gcd(ans.x, ans.y); ans.x /= g, ans.y /= g;
		print(ans.x), cout << " ", print(ans.y), cout << '\n';
	}
	return 0;
} 

T2 树

不会。

T3 洞

不会。

posted @ 2025-02-20 17:28  UKE_Automation  阅读(35)  评论(0)    收藏  举报