BZOJ 2440 完全平方數 (容斥+莫比烏斯反演+二分)
2440: [中山市選2011]完全平方數
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1673 Solved: 799
[Submit][Status][Discuss]
Description
小 X 自幼就很喜歡數。但奇怪的是,他十分討厭完全平方數。他覺得這些
數看起來很令人難受。由此,他也討厭所有是完全平方數的正整數倍的數。然而
這絲毫不影響他對其他數的熱愛。
這天是小X的生日,小 W 想送一個數給他作為生日禮物。當然他不能送一
個小X討厭的數。他列出了所有小X不討厭的數,然後選取了第 K個數送給了
小X。小X很開心地收下了。
然而現在小 W 卻記不起送給小X的是哪個數了。你能幫他一下嗎?
Input
包含多組測試資料。檔案第一行有一個整數 T,表示測試
資料的組數。
第2 至第T+1 行每行有一個整數Ki,描述一組資料,含義如題目中所描述。
Output
含T 行,分別對每組資料作出回答。第 i 行輸出相應的
第Ki 個不是完全平方數的正整數倍的數。
Sample Input
41
13
100
1234567
Sample Output
119
163
2030745
HINT
對於 100%的資料有 1 ≤ Ki ≤ 10^9, T ≤ 50
題目分析:題目要求第k個無平方因子數,我們顯然不可能把答案都求出來再查詢,這個資料範圍首先想到的是二分,對於第1-n的無平方因子數我們可以用容斥定理得到,拿總的個數減去4的倍數(-n/4個),減去9的倍數(-n/9個),但是36既是4的倍數又是9的倍數,被減了兩次,要加回來(+n/36),這樣容斥就出來了,前面的符號正好和數字開根號後對應的莫比烏斯函式相同,這樣問題就簡單了,還有一點要說明的是二分的上界開多大,這個也影響著莫比烏斯函式要開多大,我們不妨假設第k個無平方因子數不會超過2k,具體證明我也不會,但是最小的平方因子是4,也就是說每4個數裡必然有一個是平方因子數,同時因為平方因子越往後越大,可以yy出平均每四個數有不超過兩個平方因子數這個結論,所以第k個無平方因子數不會超過2k,(其實打表也可驗證),所以二分上界取2k+1即可,莫比烏斯函式開sqrt(2e9)差不多5e4的樣子
1000ms過
#include <cstdio> #include <cstring> #include <algorithm> #define ll long long using namespace std; int const MAX = 5e4; ll const INF = 2e9; int mob[MAX], p[MAX]; bool prime[MAX]; void Mobius() { int pnum = 0; memset(prime, true, sizeof(prime)); mob[1] = 1; for(int i = 2; i < MAX; i++) { if(prime[i]) { p[pnum ++] = i; mob[i] = -1; } for(int j = 0; j < pnum && i * p[j] < MAX; j++) { prime[i * p[j]] = false; if(i % p[j] == 0) { mob[i * p[j]] = 0; break; } mob[i * p[j]] = -mob[i]; } } } ll cal(int mid) { ll pos = 0; for(int i = 1; i * i <= mid; i++) pos += (ll) mob[i] * (mid / (i * i)); return pos; } int main() { Mobius(); int T; scanf("%d", &T); while(T--) { ll k; scanf("%lld", &k); ll l = 1, r = 2 * k + 1; while(l <= r) { ll mid = (l + r) >> 1; if(cal(mid) < k) l = mid + 1; else r = mid - 1; } printf("%lld\n", l); } }