区间因子和

题意简述:

告诉你有n组数据,每组数据会给你两个值,分别是 L L L R R R。 让你求在 L − R L-R LR这个范围内所有数的因数个数之和。

题目分析:

这题其实就是一个技术!

  • 首先给出一个 50 分 50分 50的思路,就是暴力打表,反正也就 1 0 5 10^5 105,空间无论如何都是不会爆的。

  • 再给出一个 100 分 100分 100的思路。我们建立一个数组,分别记录从 1 − 2 × 1 0 6 1 -2 \times 10^6 12×106 所有数字的因数个数,每一次筛的方法就是从 1 1 1开始,一直枚举到 2 × 1 0 6 2 \times 10^6 2×106,然后求出每一个数的倍数,将这个倍数的个数 + 1 +1 +1。这样,整个复杂度就会降很多。但是这样还是不行。为什么呢?

  • 仔细看题,你就会发现这样一句话:

对于 100 100 100%的数据 1 ≤ N ≤ 1 0 5 , 1 ≤ L , R ≤ 2 × 1 0 6 1≤N≤10^5,1≤L,R≤2\times10^6 1N1051LR2×106

  • 我们无论如何,都是要两重循环的对吧?
    所以复杂度一定会成为 O ( n m ) O(nm) O(nm)对吧?
    那么我们怎么优化这个复杂度呢?

  • 我们可以做一个前缀和来优化这个 O ( n m ) O(nm) O(nm)的算法。这个前缀和 s u m [   i   ] sum[\ i\ ] sum[ i ]为从 1 − i 1-i 1i 所有的数的因数个数之和。这个操作只需要 2 × 1 0 6 2\times10^6 2×106次就可以完成,而 N N N次查询的复杂度就变成了 O ( 1 ) O(1) O(1)了!

代码:

(知道你们基本上直接看这边)

#include<bits/stdc++.h>
#define int long long
#define mem(a) memset(a,0,sizeof(a))
#define set(a,b) memset(a,b,sizeof(a))
using namespace std;
int in(){   //in()
	int x=0,f=1;
	char c=getchar();
	while(!isdigit(c)){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)){
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}

const int MAXN = 2e5;
int t,l,r; 
int cnt[MAXN];
int sum[MAXN];

void init() {   //初始化 
	for (int i = 1; i <= MAXN; i++)	
		for(int j = i; j <= MAXN; j += i)
			cnt[j]++;
	
	for (int i = 1; i <= MAXN; i++)
		sum[i] = sum[i - 1] + cnt[i];
}

signed main(){
	cin >> t;
	
	init();
	
	while (t--) {
		cin >> l >> r;
		cout << sum[r] - sum[l - 1] << endl;
	}
    return 0;
}

此代码做了放抄袭, 请大家一定要养成自己思考的习惯哦!

H a p p y   E n d i n g ! Happy \ Ending ! Happy Ending!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值