UCF Local Programming Contest Round 1A E.Sum of a Function (思维 数论)

题目链接: Sum of a Function

大致题意

定义: f(x) = x的最小质因子

给出l r k 求[l, r]区间中, 最小的k个f(x)之和. 其中r - l ≤ 1E6, k <= 0.9 * (r - l + 1)

解题思路

首先我们应当抓住k的取值范围, 最大是区间长度的0.9倍. 我们应当认为这是个有用的条件, 否则给出我们限制不就没意义了吗?

此时我们可以产生一个合理的猜想: 由于我们要最小的k个f(x)相加, 那有一些比较大的质数我们应当可以直接舍弃掉, 但如何去判断呢?

已知对于一段连续数字区间而言: 若设区间长度为len. 则不是2的倍数的数字有(1 - 1/2) * len个, 不是2的倍数也不是3的倍数的数字有(1 - 1/2) * (1 - 1/3) * len … (1 - 1/2) * (1 - 1/3) * … * (1 - 1 / pk) * len

我们抛去区间长度这个因素, 那么前面的乘积就表示f(x) > pk占比是多少. 我们算算pk取到多少时, 总占比小于10%, 故我们可以得出舍弃掉的质数区间.

通过打表我们可得: 质数当取到257时, 就已经可以覆盖区间的90%了. 为了求稳我们可以提高一下上限, 我把上限设置为了1000.


到此为止, 我们质数的数量实际上非常少, 我们只需要遍历[l, r], 判断每个数字的最小质因子是否在我们筛出的质数中, 如果在的话存到数组里, 排序取前k小即可. 若不在则直接忽略掉该数字.

这里也有另外一种思路: 如果我们的质数个数比较多的话, 我们可以采用倍增法, 枚举每一个质数来进行判断.

AC代码

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E3 + 10;
int prime[N], ind;
bool vis[N];
void init(int n = N - 5) {
	vis[1] = 1;
	for (int i = 2; i <= n; ++i) {
		if (!vis[i]) prime[++ind] = i;
		for (int j = 1; prime[j] * i <= N; ++j) {
			vis[prime[j] * i] = 1;
			if (i % prime[j] == 0) break;
		}
	}
}
int main()
{
	vector<int> v;
	for (ll i = l; i <= r; ++i) {
		rep(j, ind) {
			if (i % prime[j] == 0) {
				v.push_back(prime[j]);
				break;
			}
		}
	}
	sort(v.begin(), v.end());

	ll res = 0;
	rep(i, k) res += v[i - 1];
	cout << res << endl;

	return 0;
}

/* 倍增法主函数代码
	init();
	ll l, r; int k; cin >> l >> r >> k;

	unordered_set<ll> st; //用于记录这个数字是否已经出现过了
	ll res = 0;
	rep(j, ind) { //从小到大枚举质数
    	for (ll i = (l + prime[j] - 1) / prime[j] * prime[j]; i <= r; i += prime[j]) {
			if (st.count(i)) continue;

			if (k) {
				st.insert(i);
				res += prime[j];
				k--;
			}
			if (!k) goto here;
		}
	}
    
	here: printf("%lld\n", res);
*/

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥Fau

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值