给定,求有多少对满足且为素数(表示的)。
首先,我们求出中的所有的素数,然后我们枚举。因为到的素数个数也不是很多,所以枚举也是很快的。
我们设,因此,问题被我们转化为了求有多少对,使得满足。
于是子问题的答案为。减一是因为被重复算了两次。
于是,我们就只需要预处理出素数,所有的和其前缀和即可。
表示中有多少个数与互质。
const int N=1e7+100;
typedef long long ll;
int phi[N];ll prefix_phi[N];
int prime[N],n,tot,t[N];ll ans;
void get_prime_and_phi(int n){
prefix_phi[0]=0;phi[1]=1;
for(int i=2;i<=n;i++){
if (!t[i]){
phi[i]=i-1;t[i]=i;
prime[++tot]=i;
}
for(int j=1;j<=tot;j++){
if ((ll)i*prime[j]>(ll)n) break;
t[i*prime[j]]=prime[j];
phi[i*prime[j]]=phi[i]*(prime[j]-(prime[j]<t[i]));
if (prime[j]==t[i]) break;
}
}
}
void calc_prefix_phi(int n){
for(int i=1;i<=n;i++)
prefix_phi[i]=prefix_phi[i-1]+phi[i];
}
int main(){
scanf("%d",&n);
get_prime_and_phi(n);
calc_prefix_phi(n);
for(int i=1;i<=tot;i++)
ans+=2*prefix_phi[n/prime[i]]-1;
cout<<ans;
return 0;
}
给出个数(记序列为),要求选出尽可能多的数,满足它们的最小公倍数不大于。允许数列里没数,此时这个数列的最小公倍数为。。
首先,很显然的一点是如果某个,这个是没用的。所以,的范围被我们缩小了,有用的必然满足。
如果所有的数都是一个数的约数,那么它们的最小公倍数(即LCM)必然。
加上我们发现不大,所以我们枚举,表示是所有我们选出的数的约数。问题被我们转化为了求原数列中有多少个数是的约数。
总的时间复杂度为:。


read()函数即快读函数,考虑到大家都会,不再给出。print(a,c)函数即输出一个数,同时,在它后面在输出一个字符。
- 首先,不得不说,数论很重要。无论是哪门子
OI竞赛都很喜欢考。 - 没有什么快速学懂的好方法,只有多刷多练。
- 别说什么
数论只会GCD,数论的题,哪怕是,也有很难的……
来源:CSDN
作者:ZHUYINGYE_123456
链接:https://blog.csdn.net/ZHUYINGYE_123456/article/details/104114452