首页 > 代码库 > [VIJOS1889]天真的因数分解
[VIJOS1889]天真的因数分解
题目:天真的因数分解
传送门:https://vijos.org/p/1889
题目描述:
小岛: 什么叫做因数分解呢?
doc : 就是将给定的正整数n, 分解为若干个素数连乘的形式.
小岛: 那比如说 n=12 呢?
doc : 那么就是 12 = 2 * 2 * 3 呀.
小岛: 呜呜, 好难, 居然素数会重复出现, 如果分解后每一个素数都只出现一次, 我就会.
wish: 这样来说, 小岛可以正确分解的数字不多呀.
doc : 是呀是呀.
wish: 现在问题来了, 对于给定的k, 第 k 个小岛无法正确分解的数字是多少?
分析:
(1)很明显,本题要你求出第N个mobius[i]==0的数。算法一: 求出mobius函数后回答询问,可以得30分。
(2)考虑函数$f_x=\sum_{i \leq x \&\& mobius[i]==0}1$的值,显然,这个函数满足单调性。算法二:可以二分x,询问$f_x$,比较k与$f_x$的大小。
(2.1)如何快速求$f_x$?考虑容斥原理。$f_x=\sum_i -mobius[i]*{n \over {i^2}}$。显然$i \leq \sqrt{n}$。令$mo[i]=mobius[i]$即如果有平方因子,赋值为0,否则有奇数个因子赋值为1,偶数个赋值为-1。使用线性筛法求mobius函数。
(2.2)二分的上界可以试一试,这里直接提供:(25505460948)。
代码:
1 #include <cstdio> 2 #include <iostream> 3 #define LL long long 4 const LL INF=25505460948ll; 5 bool v[1000005]; 6 int p[1000005],mo[1000005]; 7 void GetMo(){ 8 const int N=1000000; 9 for(int i=2;i<=N;++i){ 10 if(!v[i]){p[++p[0]]=i;mo[i]=1;} 11 for(int j=1;j<=p[0] && i*p[j]<=N;++j){ 12 v[i*p[j]]=true; 13 if(i%p[j]==0){mo[i*p[j]]=0;break;} 14 mo[i*p[j]]=-mo[i]; 15 } 16 } 17 } 18 LL check(LL x){ 19 LL sum=0; 20 for(LL i=1;i*i<=x;++i) 21 sum+=mo[i]*x/(i*i); 22 return sum; 23 } 24 int main(){ 25 //freopen("in.txt","r",stdin); 26 GetMo(); 27 LL k,l=0,r=INF,mid; 28 scanf("%lld",&k); 29 for(;l<=r;){ 30 mid=(l+r)>>1; 31 if(check(mid)<k) 32 l=mid+1;else r=mid-1; 33 } 34 printf("%lld",l); 35 //fclose(stdin); 36 return 0; 37 }
[VIJOS1889]天真的因数分解
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。