백준 28129 - 2022 APC가 어려웠다고요?
위 포스트는 백준 28129 - 2022 APC가 어려웠다고요?의 풀이입니다. dp[i][j] := i번째 수가 j가 되는 경우의 수 dp[i][j]=∑k=max(j−k,a[i−…
2025/03/28
Jinsoolve.
Categories
Tags
3월 안에는 꼭...
About
각 테스트케이스마다 2개의 1 ~ 의 수 a, b가 주어질 때, a를 b로 만드는데 드는 최소의 연산 횟수를 구하는 문제이다.
이때 연산은 , (짝수일 때만), 이 가능하다.
2개의 숫자를 2진수로 바꿔서 생각해보자.
예를 들어, 을 으로 만들고 싶다고 할 때, prefix가 같으므로 이때의 최소 연산 횟수는 쉽게 구할 수 있고 고정되어 있다고 할 수 있다.
이 횟수를 잘 생각해보면 prefix 길이를 뺀 나머지 길이(여기서는 2), prefix가 아닌 부분에서의 1비트 개수(여기서는 1)을 합하면 쉽게 구할 수 있다.
그럼 예를 들어서 a와 b가 주어지고, b= 인 상황이라고 하자.
a에서 , , , 을 만드는데 드는 최소 연산 횟수를 구하고 나면 각 수에서 원래의 b로 만드는 최소 횟수를 구하는 건 위에서 얘기한 것처럼 prefix가 같으므로 쉽게 구할 수 있다.
따라서 a를 위 수들로 만드는 횟수만 구하면 된다.
a가 만약 목표로 하는 수들보다 작다면 그냥 1로 더해서 만들어준다. 어차피 우리는 목표로 하는 수만 도달하면 저기부터는 알아서 최적의 루트로 b로 만들어주므로 그냥 만들어주기만 하면된다.
반면, a가 목표로 하는 수보다 큰 경우는 을 해줘서 구해준다. 물론 이때 홀수라면 을 해준다.
이런 식으로 모든 목표 수를 만들고 났을 때의 연산 횟수와 b로 증가시키는 횟수를 더해서 그 중 최솟값을 구하면 그것이 정답이 된다.
cpp1#include <bits/stdc++.h> 2 3#define endl "\n" 4#define all(v) (v).begin(), (v).end() 5#define all1(v) (v).begin()+1, (v).end() 6#define For(i, a, b) for(int i=(a); i<(b); i++) 7#define FOR(i, a, b) for(int i=(a); i<=(b); i++) 8#define Bor(i, a, b) for(int i=(a)-1; i>=(b); i--) 9#define BOR(i, a, b) for(int i=(a); i>=(b); i--) 10#define ft first 11#define sd second 12 13using namespace std; 14using ll = long long; 15using lll = __int128_t; 16using ulll = __uint128_t; 17using ull = unsigned long long; 18using ld = long double; 19using pii = pair<int, int>; 20using pll = pair<ll, ll>; 21using ti3 = tuple<int, int, int>; 22using tl3 = tuple<ll, ll, ll>; 23 24template<typename T> using ve = vector<T>; 25template<typename T> using vve = vector<vector<T>>; 26 27template<class T> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; } 28template<class T> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; } 29 30const int INF = 987654321; 31const int INF0 = numeric_limits<int>::max(); 32const ll LNF = 987654321987654321; 33const ll LNF0 = numeric_limits<ll>::max(); 34 35void solve() { 36 ll a, b; cin >> a >> b; 37 ll ans = LNF; 38 ll psum=0; 39 40 for(ll remove=0; (b>>remove)>0; remove++) { 41 ll prefix = b>>remove; 42 while(a > prefix) { 43 if(a%2 == 1) { 44 a++; 45 psum++; 46 } 47 a/=2; 48 psum++; 49 } 50 ll sum = psum; 51 sum += prefix - a; 52 sum += remove; 53 sum += __builtin_popcountll(b & ((1<<remove) - 1)); 54 55 ckmin(ans, sum); 56 } 57 cout << ans << endl; 58} 59 60int main(void) { 61 ios_base::sync_with_stdio(false); 62 cin.tie(nullptr); 63 cout.tie(nullptr); 64 65 int TC=1; 66 cin >> TC; 67 FOR(tc, 1, TC) { 68// cout << "Case #" << tc << ": "; 69 solve(); 70 } 71 72 73 return 0; 74}
위 포스트는 백준 28129 - 2022 APC가 어려웠다고요?의 풀이입니다. dp[i][j] := i번째 수가 j가 되는 경우의 수 dp[i][j]=∑k=max(j−k,a[i−…
2025/03/28
위 포스트는 백준 1055 - 끝이없음의 해설입니다. 문자열이 재귀적으로 반복하는 것을 알 수 있다. 이때 min과 max의 차이가 최대 100개 정도임을 알 수 있고, 우리는…
2025/03/05
위 포스트는 백준 1787 - 문자열의 주기 예측 의 해설입니다. 결국 부분 문자열에서 가장 짧으면서 일치하는 Prefix와 Suffix를 찾으면 된다. (해당 길이를 전체…
2025/03/05
위 포스트는 백준 8872 - 빌라봉 문제의 해설입니다. 위 문제에는 여러 개의 트리가 존재한다. 임의의 2개의 트리를 서로 이을 때 최대 시간이 최소가 되게 하기 위해서는 각…
2025/03/04