POJ 2773 Happy 2006 【数论,容斥原理+二分】
再奉上一篇容斥原理的题目,其实还是统计区间里与某个数互素的数的个数。
同类型题目:【HDU 1695 GCD】【HDU 4407 SUM】
这道题目只需要二分区间(1,x)的右端点x,统计(1,x)与s互素的数的个数即可。
#include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; typedef long long LL; #define N 1000100 bool is[N]; vector<int> pr, g; int kk; void prime() { pr.clear(); memset(is, true, sizeof(is)); pr.push_back(2); for (int i=3; i<N; i+=2) if (is[i]) { pr.push_back(i); for (int j=i+i; j<N; j+=i) is[j] = false; } } bool ok(LL x, int p) { LL v, all = x, c, k; for (int s=1; s<(1<<g.size()); s++) { c = 0, v = 1; for (int i=0; i<g.size(); i++) if (s & (1<<i)) { c++; v *= g[i]; } k = x / v; if (c % 2 == 1) all -= k; else all += k; } return all >= kk; } int main() { prime(); int m; while (scanf("%d%d", &m, &kk) == 2) { int n = m; g.clear(); for (int i=0; i<pr.size() && pr[i]<=n; i++) if (n % pr[i] == 0) { g.push_back(pr[i]); while (n % pr[i] == 0) n /= pr[i]; } LL l = 1, r = 1e17, ans, mid; while (l <= r) { mid = (l + r) >> 1; if (ok(mid, m)) { ans = mid; r = mid -1; } else l = mid + 1; } printf("%lld\n", ans); } return 0; }