神马的容斥原理实在是太神啦!
就是先二分一个数mid,看看有几个满足要求的数比他小。
查看的方法就是容斥原理。。。
res = ((2 ^ 2)倍数个数 - ((2 ^ 2) * (3 ^ 2)倍数个数 + (2 ^ 2) * (5 ^ 2)倍数个数 + ...) + (((2 ^ 2) * (3 ^ 2) * (5 ^ 2)倍数个数 + .....)) + ((3 ^ 2)倍数个数...)
我去。。。这复杂度真的能过= =
1 /************************************************************** 2 Problem: 2986 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:1512 ms 7 Memory:5688 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 12 using namespace std; 13 typedef long long ll; 14 const int N = 1000005; 15 16 int p[N], cnt; 17 bool F[N]; 18 ll n; 19 20 ll find(int f, int i, ll mid) { 21 ll res = 0, sqr; 22 for (; i <= cnt && (sqr = (ll) p[i] * p[i]) <= mid; ++i) 23 res += (ll) mid / sqr * f + find(-f, i + 1, mid / sqr); 24 return res; 25 } 26 27 void pre_work(int M) { 28 int i, j; 29 for (i = 2; i <= M; ++i) { 30 if (!F[i]) 31 p[++cnt] = i; 32 for (j = 1; i * p[j] <= M && j <= cnt; ++j) { 33 F[i * p[j]] = 1; 34 if (i % p[j] == 0) break; 35 } 36 } 37 } 38 39 int main() { 40 pre_work(N); 41 scanf("%lld", &n); 42 ll l = 1, r = (ll) 1e11, mid; 43 while (l < r) { 44 mid = (ll) l + r >> 1; 45 if (find(1, 1, mid) < n) l = mid + 1; 46 else r = mid; 47 } 48 printf("%lld ", l); 49 return 0; 50 }
(p.s. Rank.10)