B. Code For 1
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Jon fought bravely to rescue the wildlings who were attacked by the white-walkers at Hardhome. On his arrival, Sam tells him that he wants to go to Oldtown to train at the Citadel to become a maester, so he can return and take the deceased Aemon's place as maester of Castle Black. Jon agrees to Sam's proposal and Sam sets off his journey to the Citadel. However becoming a trainee at the Citadel is not a cakewalk and hence the maesters at the Citadel gave Sam a problem to test his eligibility.
Initially Sam has a list with a single element n. Then he has to perform certain operations on this list. In each operation Sam must remove any element x, such that x > 1, from the list and insert at the same position , , sequentially. He must continue with these operations until all the elements in the list are either 0 or 1.
Now the masters want the total number of 1s in the range l to r (1-indexed). Sam wants to become a maester but unfortunately he cannot solve this problem. Can you help Sam to pass the eligibility test?
Input
The first line contains three integers n, l, r (0 ≤ n < 250, 0 ≤ r - l ≤ 105, r ≥ 1, l ≥ 1) – initial element and the range l to r.
It is guaranteed that r is not greater than the length of the final list.
Output
Output the total number of 1s in the range l to r in the final sequence.
<처음에 썻던 코드>
#include<stdio.h>
int arr[100001];
int i = 0;
void DC(int x)
{
if (x == 1)
{
arr[i] = 1;
i++;
}
else
{
if (x % 2 == 1)
{
x -= 1;
DC(x / 2);
arr[i] = 1;
i++;
DC(x / 2);
}
else
{
DC(x / 2);
arr[i] = 0;
i++;
DC(x / 2);
}
}
}
int main(void)
{
int n, l, r, sum = 0;
scanf("%d %d %d", &n, &l, &r);
DC(n);
for (int j = l - 1; j < r; j++)
{
sum += arr[j];
}
printf("%d", sum);
}
내가 짠 코드를 살펴보면 만약 입력이 [10 3 10] 이라면 (101110101011101) 이므로 1~15까지의 값들을 모두 배열에 저장하여 l 부터 r 까지의 부분을 합계하여 출력하는 방식이다. n이 작은수이면 연산시간에 큰 차이를 못느끼겠지만 n의 최대값은 2^50 이다. 즉, 1.1259 X 10^15 인데 대략 1000조 정도 되는 값이다. 최악의 경우 길이 1000조 짜리 배열을 저장해야하는데 이는 말도안되는 일이다. 그리하여 24시간동안 다른 할일못하고 이 문제 풀려고 해당 범위만 조사를 하도록 코드를 구현해보려 했으나 마땅한 대안이 떠오르지 않았다. 결국 구글링을 하여서 좋은 아이디어를 얻을 수 있었다.
<다른 사람의 정답> - 참고블로그 https://cloud.tencent.com/developer/article/1086462
#include <stdio.h>
typedef long long ll;
ll n, l, r, s = 1, ans;
void solve(ll a, ll b, ll l, ll r, ll d) // a = 시작범위, b = 끝 범위, d = 나뉘는 수
{
if (a > b || l > r) return;
else
{
ll mid = (a + b) / 2;
if (r < mid) solve(a, mid - 1, l, r, d / 2);
else if (mid < l) solve(mid + 1, b, l, r, d / 2);
else {
ans += d % 2;
solve(a, mid - 1, l, mid - 1, d / 2);
solve(mid + 1, b, mid + 1, r, d / 2);
}
}
}
int main()
{
scanf("%lld %lld %ld", &n, &l, &r);
long long p = n;
while (p >= 2) // s = 길이
{
p /= 2;
s = s * 2 + 1;
}
solve(1, s, l, r, n);
printf("%d\n", ans);
return 0;
}
기본적인 아이디어를 보자면 범위가 l 부터 r 까지 합을 구하는데
mid 값(여기에서 mid는 범위의 길이, ex : 만약 입력값이 10이라면 101110101011101 이므로 길이가 15이다.) 기준으로
1. l이 mid보다 크다면 다시 mid+1 부터 b 까지의 범위로 재귀를 하고
2. r이 mid보다 작을 경우 a 부터 mid - 1 까지의 범위를 재귀한다.
3. 1, 2번의 경우가 아니라면 중간 값(mid값 X)은 항상 범위 내에 있다는 말이므로 중간 값이 홀수면 +1, 짝수면 +0
그렇다면 해당 범위만 조사하고 r - l 의 최대값이 10만이므로 무리없이 연산이 가능하다.
'🧩PS > 🥇Hard' 카테고리의 다른 글
[C/C++] Codeforce 455A - Boredom (DP) (0) | 2020.04.30 |
---|---|
[C/C++] Codeforce 189A - Cut Ribbon (DP, Brute Force) (0) | 2020.04.30 |
[C/C++] Codeforce 448C - Painting Fence (분할정복, Divide and Conquer) (0) | 2020.04.13 |
[C/C++] 백준 10434번 행복한 소수 (0) | 2020.04.11 |
[C/C++] 백준 1520번 내리막 길 - 동적 계획법(DP, Dynamic Programming) 사용 풀이법 (0) | 2020.04.11 |