列表

详情


NC222912. 小䓤的凸包

描述

定义 ,其中 (x,y) 表示 (0,0) 指向 (x,y) 的向量,一个向量 (x,y) 的斜率为一个实数 。再定义一个向量 (i,j) 的权值为 ,其中 a,b 为给定常量。

小䓤最初有 S_n 中的所有向量,他想要在其中选出一些向量按照斜率从小到大顺次拼接成一个右下凸壳,其中他希望每种在 S_n 中出现的斜率都出现在选择的向量中且凸壳的横坐标极差(也即选出的向量的横坐标之和)最小。容易发现给定 n 后小䓤在上述要求下选出的集合是定的。

做完上一步操作后,他会用一条斜率为 的线去切这个凸壳,这条线会从无穷远的下方向上移动直到碰到凸壳上的点并截取其右上方的部分。

给出 a,b 求对 S_n 做上述两步操作后的凸壳上的向量的代价和,答案对 取模。

下面举一个例子说明上述过程。



那么第一步操作后我们会选出 这三个向量,对斜率 的向量 (1,1),(2,2) 我们只保留 (1,1) 因为
(2,2) 斜率与 (1,1) 相同但其横向跨度更长。第二步使用斜率为 去切割凸壳后剩下的凸壳上的向量为 ,代价和为

输入描述

共一行五个整数 

输出描述

一个整数表示每组询问的答案

示例1

输入:

2 4 3 1 1

输出:

3

说明:

与题目中举的例子相同

示例2

输入:

50 2 5 4 3

输出:

928433684

示例3

输入:

500000 3 4 2 2

输出:

15675121

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 3149ms, 内存消耗: 218760K, 提交时间: 2021-11-19 21:55:42

#include <bits/stdc++.h>
using namespace std;

typedef long long s64;
const int N = 1e8 + 5, D = 998244353;
s64 pow_mod(s64 x, int y = D - 2) {
	s64 ans = x;
	--y;
	while (y) {
		if (y & 1) ans = ans * x % D;
		x = x * x % D;
		y >>= 1;
	}
	return ans;
}
int n;
char miu[N];
bool mark[N];
int pr[N / 10], pcnt;
void init(int n) {
	miu[1] = 1;
	for (int i = 2; i <= n; ++i) {
		if (!mark[i]) {
			pr[++pcnt] = i;
			miu[i] = -1;
		}
		for (int j = 1; j <= pcnt; ++j) {
			int p = pr[j];
			if (i * p > n) break;
			mark[i * p] = 1;
			if (i % p == 0) break;
			miu[i * p] = -miu[i];
		}
	}
}
int q[N];
s64 F(int n, int x, int y, int a, int b) {
	if (y > x) y = x = 1;
	int t = 0;
	int i = 1;
	while (i <= n) {
		q[++t] = i;
		i = n / (n / i) + 1;
	}
	q[t + 1] = n + 1;
	int j = 0;
	s64 ans = 0;
	s64 w2 = 0, s_i = 0;
	i = 0;
	for (int h = t; h; --h) {
		int d = q[h];
		int m = n / d;
		s64 w1 = 0;
		for (int i = d; i < q[h + 1]; ++i)
			if (miu[i] == 1)
				w1 += pow_mod(i, a + b);
			else if (miu[i] == -1)
				w1 -= pow_mod(i, a + b);
		w1 %= D;
		while (j < m) {
			++j;
			while ((s64)(i + 1) * x < (s64)y * j) {
				++i;
				(s_i += pow_mod(i, a)) %= D;
			}
			(w2 += pow_mod(j, b) * s_i) %= D;
		}
		(ans += w1 * w2) %= D;
	}
	return ans;
}

int main() {
#ifdef kcz
	freopen("1.in", "r", stdin); //freopen("1.out","w",stdout);
#endif
	int x, y, a, b;
	cin >> n >> y >> x >> a >> b;
	int d = __gcd(x, y);
	x /= d;
	y /= d;
	init(n);
	s64 ans = F(n, x, y, a, b);
	if (y > x) {
		ans = (ans + 1 + F(n, 1, 1, b, a) - F(n, y, x, b, a)) % D;
	} else if (x <= n && y <= n)
		(ans += pow_mod(y, a) * pow_mod(x, b)) %= D;
	cout << (ans % D + D) % D << endl;
}

上一题