백준 2737번, 연속 합 풀이
2021. 1. 27. 12:23ㆍProblem Solving/백준
문제
풀이
$n$을 $a$부터 $b$까지의 합으로 나타내면 아래와 같습니다.
$$ n = a + a + 1 +\ \cdot\cdot\cdot \ + b - 1 + b $$
$a$부터 $b$까지 $k$개를 뽑는다고 하면 첫째항이 $a$이고 끝항이 $a + k - 1$가 되며, 등차가 1입니다.
등차수열의 합 공식에 의해서
$$ n = \frac{k(2a + k - 1)}{2} $$
로 나타낼 수 있습니다. 식을 정리하면
$$ k^2 + k(2a - 1) - 2n = 0 $$
으로 나타낼 수 있고, 근의 공식에 의해서
$$ k = \frac{1 - 2a \pm \sqrt{4a^2 - 4a + 1 + 8n}}{2} $$
이 됩니다. 뽑는 수 $k$를 최대로 하려면, 첫째항 $a$를 $ 1$로 두면 됩니다.
따라서, $k$의 범위는
$$ 2 \leq k \leq \frac{-1 + \sqrt{8n + 1}}{2} $$
$k$가 정해지면, $a$의 값 역시 구할 수 있습니다. 위 2차 방정식을 $a$에 대해 정리하면,
$$ a = \frac{n}{k} - \frac{k}{2} + \frac{1}{2} $$
위와 같습니다.
문제에서 $n$의 범위가 $2^{31}$보다 작다고 하였기 때문에 $k$의 최댓값은 $O(\sqrt{n})$ 이므로 시간 내에 통과할 수 있습니다.
소스코드
#include <bits/stdc++.h>
#define all(v) v.begin(), v.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef unordered_map<int, int> mpii;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T = 1;
cin >> T;
while (T--) {
ld n;
cin >> n;
ld lim = (-1 + sqrt(8 * n + 1)) / 2; //k의 최댓값
int ans = 0;
for (ld k = 2; k <= lim; k++) {
ld a = -(k / 2) + 0.5 + (n / k);
if (a == (ll)a) ans++;
}
cout << ans << "\n";
}
}
'Problem Solving > 백준' 카테고리의 다른 글
백준 2201번, 이친수 찾기 풀이 (0) | 2021.02.05 |
---|---|
백준 2143번, 두 배열의 합 풀이 (0) | 2021.01.29 |
백준 2560번, 짚신벌레 풀이 (0) | 2021.01.26 |
백준 10986번, 나머지 합 풀이 (0) | 2021.01.23 |
백준 1407번, 2로 몇 번 나누어질까 풀이 (0) | 2021.01.17 |