【2】ABC412E - LCM Sequence 解题报告

题意:给你一个区间 \([l,r]\),设 \(a_i\) 是 \(1\) 到 \(i\) 的最小公倍数的值。问当 \(l\leq i\leq r\) 时出现过多少个不同的 \(a_i\),数据范围满足 \(1\leq l,r\leq 10^{14},r-l\leq 10^7\)。

这题我主要通过对最小公倍数的变动次数,来统计答案。

对原有质因数范围的判定

对于这个题,我们自然想到对 \(a_l\) 分解质因数。注意到 \(> 10^7\) 的质因子需要再出现一次的话就需要一个 \(>10^{14}\) 的数,所以我们考虑所有质因子只考虑 \(\leq 10^7\) 的即可。

情况:出现原有的质因子

我们发现对于一个可能出现新次数的质因数 \(p\),设原先出现次数为 \(e\),那么我们要判断是否出现了 \(p^e\),\(p^{e+1}\),\(p^{e+2}\) 等更多的出现次数。我们注意到 \(e\ge 2\),那么枚举更多可能出现个数的复杂度就将会是 \(\mathcal O(\log_{e}r)\)。这是可以接受的。

具体的,我们枚举所有可能的数 \(p\),暴力计算是否 \(p^x\leq r\),其中 \(x\) 是一个从 \(e+1\) 开始不断往上枚举的数。当 \(p^x\) 有一个倍数是在 \([l,r]\) 之间的,那么我们就证明了会因为 \(p^x\) 导致数的变化,统计出这导致的变动次数。

情况:出现新的质因子

这个情况相当于 \([l,r]\) 之中出现了质数,那么我们要证明不会出现不存在的质因子。

证明:假设出现一个 \(10^7<p<l\),且 \(p^2\leq r\) 的质因子,落在 \([l,r]\) 里。那么我们就会发现,出现了 \(10^{14}\leq r\),不可能出现。

所以 \(p^2>r\),所以 \(l\leq p\leq r\) 就是一个质数。那么我们就可以想一个办法处理出 \(l<p\leq r\) 的质数。注意不能取到 \(l\),因为这个质数不会造成修改。我们想如何统计这个质数。注意我们有一个埃筛,是 \(\mathcal O(n\log \log n)\) 的(证明略),我们考虑将 \(r-l\leq 10^7\) 这个条件应用。我们发现因为我们可以求出 \(\leq 10^7\) 的所有质数,并且其他的质数 \(10^7<p\) 是不能用于筛去 \([l,r]\) 内的质数,所以我们可以只用 \(2\leq p\leq 10^7\) 的质数去筛出 \([l,r]\) 内的质数。这很有用,我们可以精确筛去 \([l,r]\) 内的合数,并且复杂度也是可以接受的。

总方法

那么到现在,我们统计了:

  • 因为质因数次数增加导致的变动。
  • 因为出现新的质数增加导致的变动。

这包含了所有的答案,注意出现数量要加上初始数量的 \(1\)。这样,我们就用不超过 \(\mathcal O(n\log n)\) 的复杂度解决问题,这里 \(n=r-l\)。我们应当可以在要求的时限内通过。

这里给出我的出错位置:

  1. 注意 \([l,r]\) 中取 \(p\) 倍数需要用好三目运算符,代码里的比较乱,大致就是 \(l\) 的下区间要向上取整,\(r\) 的上区间要向下取整,可以结合自己的写法。
  2. 注意极限可能会出现一个 \(10^7\times 10^{14}\) 的乘法,需要开好朋友 __int128。
  3. 再次强调枚举新质数范围不要包括 \(l\) 范围,原因见上文。不然你会因为只错一个点破防。
  4. 注意到问的是出现数量,这个数就是我们求出来的变动数量加上 \(1\)。
  5. 还有一个,我们不要乱用 map,可以加上一个偏移值 \(-l\) 来用数组来存储,不然直接给你卡超时高达 \(10000+\) 毫秒。

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e7+10;
int l,r,ans;
int gg(int x,int y){
	if(!y)
		return x;
	return gg(y,x%y);
}
vector<int>Prime;
bool is[N];
int hh[N];
vector<pair<int,int> >l_lcm;
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>l>>r;
	memset(is,1,sizeof(is));
	is[0]=is[1]=0;
	for(int i=2;i<=(int)1e7;i++)if(is[i]){
		Prime.push_back(i);
		for(int j=i+i;j<=(int)1e7;j+=i)is[j]=0;
		for(int j=(l%i?(l/i+1)*i:l);j<=(r/i)*i;j+=i)if(j!=i)
			hh[j-l]=1;
	}
	for(auto p:Prime){
		if(p*p>r)
			break;
		int e=0;
		__int128 mul=1;
		while(mul*p<=l){
			++e;
			mul*=p;
		}
		l_lcm.push_back({p,e});
	}
	for(auto v:l_lcm){
		int val=1;
		if(v.second==0)
			val*=v.first;
		for(int i=1;i<=v.second;i++)
			val=val*v.first;
		__int128 mul=val;
		while(mul*v.first<=r){
			val=val*v.first;
			int ll=(l%val?(l/val+1):l/val),rr=r/val;
			ans+=bool(rr-ll+1);
			mul*=v.first;
		}
	}
	for(int j=l;j<=r;j++)
		if(!hh[j-l]&&j>l)++ans;
	cout<<ans+1;
	return 0;
}

https://www.luogu.com.cn/article/e0feor33

posted @ 2026-10-12 11:49  Ivan422  阅读(6)  评论(0)    收藏  举报