6782. 현주가 좋아하는 제곱근 놀이 (D5) 본문
문제링크 : https://www.swexpertacademy.com/main/code/problem/problemSolver.do?contestProbId=AWgqsAlKr9sDFAW0
< 입력 >
정수 N (1<=N<=10^12)
< 출력 >
N을 2로 바꾸는데 필요한 횟수
< 풀이 >
D5라서 겁먹고 시작했는데 단순한 문제였다.
문제가 어렵다기 보다는 테스트 케이스가 10,000개에 수의 범위가 10^12기 때문에
어떤 방법으로 시간을 줄여서 풀 것인지가 중요한 문제이다.
따로 줄이는 과정을 생각해보지도 않았고 while문 돌렸는데 풀려서.. 다른 사람들이 어떤 방법으로
시도를 했고 시간초과로 고민을 하는지는 잘 모르겠다.
-----------------------------------------------------------------------------------------------------------------------
아마도 "더 많이 더한 후에 제곱근을 하면 더 좋은 경우가 나올 수 있지 않을까?"라는 생각으로 다양한 방법을 생각해본 것이 오히려 틀린 이유라고 생각한다.
이 문제는 가장 가까운 제곱수를 찾는 것이 핵심이다.
제곱을 한 값이 커질수록 제곱수와 제곱수 사이의 간격이 커지기 때문에 오히려 더해서 다음 제곱수를 찾는 과정에서 더 많은 조작이 필요한 것이 자명한 사실이기 때문이다.
-----------------------------------------------------------------------------------------------------------------------
먼저, 숫자 N을 조작할 수 있는 방법은 2가지이다.
1. N에 1을 더한다.
2. N의 제곱근이 정수일 경우 N에 제곱근을 씌운다.
이 조건을 통해 알 수 있는 점은 N은 1번 조작에 의해서만 증가하고 2번 조작에 의해서만 감소한다는 점이다.
그러므로 N이 1인 경우를 제외하면 N을 제곱근이 정수일때까지 더하고 제곱근을 씌워주면 된다.
수를 바꿀 수 있는 여러가지 방법이 존재하지 않다는 점에서 단순하게 느껴진 문제였다.
사용한 방법은 while문의 시작에서 N에 제곱근을 씌운 값을 다시 제곱을 한다.
제곱근을 씌울 때 (long long)을 씌우게 되면 n보다 작거나 같은 제곱수들 중 최대값을 구할 수 있다.
그렇게 구한 값에 -N을 한 결과를 temp라는 변수에 넣는다.
이 때, temp가 0이라면 N이 제곱수라는 뜻이므로 제곱근을 씌우고 횟수에 1을 더한다.
그 외의 경우는 N이 제곱수가 아니라는 뜻이므로
(long long)sqrt(N) +1 을 제곱한 수가 될 때까지 더해야한다.
그 차이만큼 횟수에 더하고 제곱수가 되었으므로 제곱근을 씌우기 위한 1번의 횟수를 더 더한다.
이러면 .. 끝 !
- 소스 코드 -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include<iostream> #include<math.h> using namespace std; typedef long long ll; int main(void){ int T; cin>>T; for(int test_case=1;test_case<=T;test_case++){ // n이 10^12까지므로 long long으로 받기 ll n; scanf("%lld",&n); ll result=0; while(n!=2){ // n이 1일 경우를 예외처리 해주지 않으면 무한루프 if(n==1){ result++; break; } // n이 제곱수인지 따지는 식 ll temp=0ll+pow((ll)sqrt(n),2)-n; // 만약 0이라면 제곱수이므로 루트를 씌운다. if(temp==0){ n=(ll)sqrt(n); result+=1; }else{ // 0이 아니라면 제곱수가 될때까지 1씩 증가시켜줘야 한다. // 그래서 sqrt(n)+1의 제곱과의 차이만큼 1씩 증가시키고 // 제곱근 씌우는 횟수 1번을 더한다. result+=pow((ll)sqrt(n)+1,2)-n; result+=1; n=sqrt(n)+1; } } // lld 출력하면 끝 ! printf("#%d %lld\n",test_case,result); } } | cs |
'알고리즘 문제풀기 > SW Expert Academy' 카테고리의 다른 글
5521. 상원이의 생일파티 (D5) (0) | 2019.01.17 |
---|---|
6697. 이현이의 괄호 문자열 (D5) (0) | 2019.01.16 |
3131. 100만 이하의 모든 소수 (D3) (0) | 2019.01.15 |
5604. [Professional] 구간 합 (0) | 2019.01.08 |
6485. 삼성시의 버스 노선 (D3) (0) | 2019.01.07 |