BZOJ-1968-[Ahoi2005]COMMON 约数研究
Posted I__am
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ-1968-[Ahoi2005]COMMON 约数研究相关的知识,希望对你有一定的参考价值。
Description
Input
Output
Sample Input
Sample Output
题解
这道题刚开始以为是线性筛
但是有一种更优的算法
考虑因子中有因子i的数的数量
1 //考虑有多少个数是以i为因子的 2 #include<bits/stdc++.h> 3 using namespace std; 4 int n,ans; 5 int main(){ 6 scanf("%d",&n); 7 for (int i=1;i<=n;i++) 8 ans+=n/i; 9 printf("%d\n",ans); 10 return 0; 11 }
这个代码灰常短,也挺好理解的
Solution2:
但是如果想不到怎么办
那就只好强上线性筛了
这里先说一下
num[i]表示i的因子个数,Min[i]表示i的最小质因子的次数
我们可以通过约数个数定理来求一个数的因子个数
传送门:https://baike.so.com/doc/5806281-6019081.html
不难发现一个质数的因子个数为2(1和它本身),最小质因子的次数为1
我们在筛质数的时候判断一下prime[j]是否为i的最小质因子
如果是
num[i*prime[j]]等于num[i]/(Min[i]+1)*(Min[i]+2)
Min[i*prime[j]]等于Min[i]+1 //最小质因子次数+1
如果不是
num[i*prime[j]]就等于num[i]*num[prime[j]] //符合积性函数
Min[i*prime[j]]等于1 //i*prime[j]的最小质因子为prime[j]且只有1次
1 //线性筛 2 #include<bits/stdc++.h> 3 #define N 1000005 4 using namespace std; 5 int n,ans,cnt; 6 int prime[N],num[N],Min[N]; 7 bool flag[N]; 8 int main(){ 9 scanf("%d",&n); 10 num[1]=1; 11 for (int i=2;i<=n;i++){ 12 if (!flag[i]){ 13 prime[++cnt]=i; 14 num[i]=2; 15 Min[i]=1; 16 } 17 for (int j=1;j<=cnt&&i*prime[j]<=n;j++){ 18 flag[i*prime[j]]=true; 19 if (!(i%prime[j])){ 20 num[i*prime[j]]=num[i]/(Min[i]+1)*(Min[i]+2); 21 Min[i*prime[j]]=Min[i]+1; 22 break; 23 } 24 num[i*prime[j]]=num[i]*num[prime[j]]; 25 Min[i*prime[j]]=1; 26 } 27 } 28 for (int i=1;i<=n;i++) 29 ans+=num[i]; 30 printf("%d\n",ans); 31 return 0; 32 }
以上是关于BZOJ-1968-[Ahoi2005]COMMON 约数研究的主要内容,如果未能解决你的问题,请参考以下文章
bzoj1968: [Ahoi2005]COMMON 约数研究
BZOJ 1968: [Ahoi2005]COMMON 约数研究
BZOJ-1968: [Ahoi2005]COMMON 约数研究 (思想)
BZOJ 1968 [Ahoi2005]COMMON 约数研究