[bzoj2440] [中山市選2011]完全平方數
阿新 • • 發佈:2019-01-02
Description
小 X 自幼就很喜歡數。但奇怪的是,他十分討厭完全平方數。他覺得這些數看起來很令人難受。由此,他也討厭所有是完全平方數的正整數倍的數。然而這絲毫不影響他對其他數的熱愛。
這天是小X的生日,小 W 想送一個數給他作為生日禮物。當然他不能送一個小X討厭的數。他列出了所有小X不討厭的數,然後選取了第 K個數送給了小X。小X很開心地收下了。
然而現在小 W 卻記不起送給小X的是哪個數了。你能幫他一下嗎?
Input
包含多組測試資料。檔案第一行有一個整數 T,表示測試資料的組數。
第2 至第T+1 行每行有一個整數Ki,描述一組資料,含義如題目中所描述。
Output
含T 行,分別對每組資料作出回答。第 i 行輸出相應的
第Ki 個不是完全平方數的正整數倍的數。
Sample Input
4
1
13
100
1234567
Sample Output
1
19
163
2030745
Solution
顯然滿足單調性,可以二分。
然後問題轉化為了\(1\)到\(n\)內有多少個滿足條件的數。
對於一個滿足條件的數,即每個質因子的指數都是1。
對於一個數\(x=\prod_{i=1}^kp_i^{a_i}\cdot s\),其中前面的\(\prod\)表示\(\forall i,a_i\geqslant 2\)的部分,後面是剩下的。
考慮當且僅當\(k=0\)時,這個數才會被計一次,\(k\ne 0\)時,一次都不會記。
可以想到這樣一個函式:
\[ \sum_{d|n}\mu(d)=[n=1] \]
於是可以列舉每個完全平方數\(x^2\),剩下的質因子隨便填,然後乘上\(\mu(x)\),這樣正好可以滿足每個滿足條件的數被記一次。
#include<bits/stdc++.h> using namespace std; #define int long long #define ONLINE_JUDGE #ifdef ONLINE_JUDGE #define getchar() ((p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2)?EOF:*p1++) #endif namespace fast_IO { char buf[1<<21],*p1=buf,*p2=buf; template <typename T> inline void read(T &x) { x=0;T f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f; } template <typename T,typename... Args> inline void read(T& x,Args& ...args) { read(x),read(args...); } char buf2[1<<21],a[80];int p,p3=-1; inline void flush() {fwrite(buf2,1,p3+1,stdout),p3=-1;} template <typename T> inline void write(T x) { if(p3>(1<<20)) flush(); if(x<0) buf2[++p3]='-',x=-x; do {a[++p]=x%10+48;} while(x/=10); do {buf2[++p3]=a[p];} while(--p); buf2[++p3]='\n'; } template <typename T,typename... Args> inline void write(T x,Args ...args) { write(x),write(args...); } } using fast_IO :: read; using fast_IO :: write; using fast_IO :: flush; const int maxn = 1e6+10; int pri[maxn],tot,vis[maxn],mu[maxn]; void sieve() { mu[1]=1; for(int i=2;i<maxn;i++) { if(!vis[i]) pri[++tot]=i,mu[i]=-1; for(int j=1;j<=tot&&i*pri[j]<maxn;j++) { vis[i*pri[j]]=1; if(i%pri[j]==0) break; mu[i*pri[j]]=-mu[i]; } } } int check(int n) { int tmp=0; for(int i=1;i*i<=n;i++) tmp=tmp+mu[i]*n/(i*i); return tmp; } void solve() { int n,l,r,mid,ans=1;read(n);l=1,r=n*2; while(l<=r) { mid=((l+r)>>1); if(check(mid)>=n) ans=mid,r=mid-1; else l=mid+1; }write(ans); } signed main() { sieve(); int t;read(t);while(t--) solve(); flush(); return 0; }