문제링크
https://www.acmicpc.net/problem/1557
1557번: 제곱 ㄴㄴ
어떤수 N이 1이 아닌 제곱수로 나누어지지 않을 때, 이 수를 제곱ㄴㄴ수라고 한다. 제곱수는 4, 9, 16, 25와 같은 것이고, 제곱ㄴㄴ수는 1, 2, 3, 5, 6, 7, 10, 11, 13, ...과 같은 수이다. K가 주어졌을 때, K
www.acmicpc.net
풀이
- f(x): x 이하의 제곱 ㄴㄴ 수 개수
- f(t)=K 인 제일 작은 t 가 답이고 parametric search 로 찾는다.
- f(t) 구현
- t− (√t 이하의 소수들의 조합으로 구성된 수들의 제곱의 합집합 개수)
- 포함배제의 원리로 홀수종류 포함은 더하기, 짝수종류 포함은 빼기
코드
#include <bits/stdc++.h> using namespace std; #define all(v) (v).begin(), (v).end() #define rall(v) (v).rbegin(), (v).rend() int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); vector<long long> prime; vector<int> isPrime(sqrt(2e9) + 1, true); isPrime[0] = isPrime[1] = false; for (int i = 2; i * i < isPrime.size(); ++i) { if (!isPrime[i]) continue; for (int j = i * i; j < isPrime.size(); j += i) { isPrime[j] = false; } } for (int i = 2; i < isPrime.size(); ++i) { if (isPrime[i]) prime.push_back(i); } // 1 이상 x 이하 제곱 ㄴㄴ 수 개수 auto getNum = [&](long long x) { // cnt, idx, num queue<tuple<int, int, long long> > q; for (int i = 0; i < prime.size(); ++i) { auto e = prime[i]; if (e * e > x) break; q.push({1, i, e}); } long long ret = 0; map<int, int> visited; while (q.size()) { auto [fcnt, fidx, fn] = q.front(); q.pop(); ret += (fcnt & 1 ? 1LL : -1LL) * (x / (fn * fn)); for (int i = fidx + 1; i < prime.size(); ++i) { auto e = prime[i]; if (fn * e * fn * e > x) break; if (fn % e == 0) continue; q.push({fcnt + 1, i, fn * e}); } } return x - ret; }; long long lo = 0; long long hi = 2e9; long long K; cin >> K; while (lo + 1 < hi) { long long mid = (lo + hi) >> 1; if (getNum(mid) < K) lo = mid; else hi = mid; } cout << hi << '\n'; }
728x90
'PS > BOJ' 카테고리의 다른 글
백준 1082번: 방 번호 (0) | 2023.06.10 |
---|---|
백준 22581번: IkaNumber (0) | 2022.07.12 |
백준 1102번: 발전소 (0) | 2022.07.02 |
백준 2011번: 암호코드 (0) | 2022.07.02 |
백준 13546번: 수열과 쿼리 4 (0) | 2022.03.08 |