【2】ABC412E - LCM Sequence 解题报告【数学】
题意:给你一个区间
这题我主要通过对最小公倍数的变动次数,来统计答案。
对原有质因数范围的判定
对于这个题,我们自然想到对
情况:出现原有的质因子
我们发现对于一个可能出现新次数的质因数
具体的,我们枚举所有可能的数
情况:出现新的质因子
这个情况相当于
证明:假设出现一个
10^7<p<l ,且p^2\leq r 的质因子,落在[l,r] 里。那么我们就会发现,出现了10^{14}\leq r ,不可能出现。
所以
总方法
那么到现在,我们统计了:
- 因为质因数次数增加导致的变动。
- 因为出现新的质数增加导致的变动。
这包含了所有的答案,注意出现数量要加上初始数量的
这里给出我的出错位置:
- 注意
[l,r] 中取p 倍数需要用好三目运算符,代码里的比较乱,大致就是l 的下区间要向上取整,r 的上区间要向下取整,可以结合自己的写法。 - 注意极限可能会出现一个
10^7\times 10^{14} 的乘法,需要开好朋友__int128。 - 再次强调枚举新质数范围不要包括
l 范围,原因见上文。不然你会因为只错一个点破防。 - 注意到问的是出现数量,这个数就是我们求出来的变动数量加上
1 。 - 还有一个,我们不要乱用
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;
}