「vijos1889」天真的因数分解
描述
小岛: 什么叫做因数分解呢?
doc : 就是将给定的正整数n, 分解为若干个素数连乘的形式.
小岛: 那比如说 n=12 呢?
doc : 那么就是 12 = 2 X 2 X 3 呀.
小岛: 呜呜, 好难, 居然素数会重复出现, 如果分解后每一个素数都只出现一次, 我就会.
wish: 这样来说, 小岛可以正确分解的数字不多呀.
doc : 是呀是呀.
wish: 现在问题来了, 对于给定的k, 第 k 个小岛无法正确分解的数字是多少?
格式
输入格式
输入只有一行, 只有一个整数 k.
输出格式
输出只有一行, 只有一个整数, 表示小岛无法正确分解出来的第k个数字.
限制
对于30%的数据, k <= 2,000,000
对于100%的数据, 1 <= k <= 10,000,000,000
提示
前 10 个小岛无法正确分解出来的数字依次是: 4 8 9 12 16 18 20 24 25 27
题解
莫比乌斯反演。。。
二分+判定
小于x的可以正确分解的数字个数是 Σmu[i]*(x/i^2)
然后可以稍微把mu函数改改即可。。。
二分的上界可以测一下。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<set> #include<ctime> #include<vector> #include<cmath> #include<algorithm> #include<map> #define N 160000 #define ll long long using namespace std; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } ll ans,K; int tot; int mu[200005],pri[200005]; bool mark[200005]; void getmu() { for(int i=2;i<=N;i++) { if(!mark[i])pri[++tot]=i,mu[i]=1; for(int j=1;j<=tot&&pri[j]*i<=N;j++) { mark[i*pri[j]]=1; if(i%pri[j]==0){mu[i*pri[j]]=0;break;} else mu[i*pri[j]]=-mu[i]; } } } ll cal(ll x) { ll sum=0,t=sqrt(x); for(ll i=2;i<=t;i++) sum+=x/(i*i)*mu[i]; return sum; } int main() { getmu(); K=read(); ll l=K,r=25505460948LL; while(l<=r) { ll mid=(l+r)>>1; if(cal(mid)>=K)ans=mid,r=mid-1; else l=mid+1; } printf("%lld\n",ans); return 0; } |
Subscribe