본문 바로가기

PS - 알고리즘

백준 19825 - Minimal Product

 

 

문제 번역

주어진 정수 배열 $a_1,\dots,a_n$에서, $i<j$이고 $a_i<a_j$인 두 인덱스 $i$와 $j$를 찾아야 합니다. 그리고 이 때 $a_i \cdot a_j$의 곱이 가능한 한 작게 되도록 해야 합니다.

- chat GPT -

 

step 1

더보기

$n$이 20000000이기 때문에 $O(n \log n)$도 터집니다

$j$가 정해졌을 때 최적의 $i$를 구할 것입니다. $a_j$가 0 미만인 경우와 이상인 경우로 나누어 봅시다.

  • 0 미만인 경우 : $a_i$는 항상 음수입니다. $a_i \cdot a_j$가 작아지려면 $a_i$는 가능한 후보들 중 가장 큰 수가 되어야 합니다. 이 경우 $a_i \cdot a_j$는 항상 양수입니다.
  • 0 이상인 경우 : $a_i$가 양수, 음수 여부에 관계없이 가장 작은 값을 선택해야 합니다. 

step 2

더보기

$a_i < 0, a_j >= 0$인 경우가 있다고 합시다. 이 경우 정답은 음수이고 $a_j < 0$인 경우는 고려할 필요가 없습니다.

그럼 모든 $a_j >= 0$에 대해서 가장 작은 $a_i$를 구하면 됩니다.

step 3

더보기

$a_i < 0, a_j >= 0$인 경우가 없다고 합시다. 이 경우

 

( >=0 인 수들), (<0 인 수들)

 

이런 색으로 배치되어 있습니다. 물론 ( >=0 인 수들)이 없거나 (<0 인 수들)이 없을 수도 있습니다. 이 두 영역은 서로 영향을 미치지 못하므로 따로 계산해 줄 것입니다.

 

( >=0 인 수들)는 위에서 했던 방식으로 진행할 수 있습니다.

 

(<0 인 수들)인 수는 결과가 항상 양수이기 때문에 전부 $-1$을 곱해 줄 것입니다. 다만 이렇게 하면 크기 관계가 반대로 되기 때문에 $i<j$이고 $a_i>a_j$인 수를 찾는 문제로 바뀝니다. 그래서 $-1$ 을 곱한 뒤 전체 영역을 뒤집어 줄 것입니다. 이렇게 하면 ( >=0 인 수들)과 같은 방식으로 계산할 수 있습니다.

주의할 점

더보기

$a$를 계산해 주는 과정에서 long long도 터집니다. unsigned long long 을 사용하고 계속 $2^{32}$로 나누어 줘야 계산이 잘 됩니다. 

코드

더보기
#define _CRT_SECURE_NO_WARNINGS
#define ll long long
#include <cstdio>
#include<vector>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
ll b[10000010], pos[10000010];
int main() {
    ll m, i;
    ll n, l, r, x, y, z,dab;
    scanf("%lld", &m);
    while(m--) {
        ll ez = 0;
        scanf("%lld%lld%lld%lld%lld%lld%lld%lld", &n, &l, &r, &x, &y, &z, &b[1], &b[2]);
        for (i = 3;i <= n;i++) {
            b[i] = ((unsigned ll)(b[i - 2]) * x % (1ll << 32)) + ((unsigned ll)b[i - 1] * y % (1ll << 32)) + z;
            b[i] %= (1ll << 32);
        }
        for (i = 1;i <= n;i++) {
            ll t = b[i] % (r - l + 1) + l;
            b[i] = t;
            if (i > 1 && b[i - 1] < 0 && b[i] >= 0) ez=1;
        }

        dab = 9000000000000000000ll;
        if (ez == 1) {
            ll minn = b[1];
            for (i = 2;i <= n;i++) {
                if (minn<b[i] && dab>minn * b[i]) dab = minn * b[i];
                minn = min(minn, b[i]);
            }
        }
        else {
            i = 1;
            if (b[1] >= 0) {
                ll minn = b[1];
                for (i = 2;i <= n;i++) {
                    if (b[i] < 0) break;
                    if (minn<b[i] && dab>minn * b[i]) dab = minn * b[i];
                    minn = min(minn, b[i]);
                }
            }

            ll s = i;
            for (i = s;i <= n;i++) b[i] *= -1;
            ll minn = b[n];
            for (i = n - 1;i >= s;i--) {
                if (minn<b[i] && dab>minn * b[i]) dab = minn * b[i];
                minn = min(minn, b[i]);
            }
        }
        if (dab == 9000000000000000000ll) printf("IMPOSSIBLE\n");
        else printf("%lld\n", dab);
    }
    return 0;
}

 

'PS - 알고리즘' 카테고리의 다른 글

백준 31749 - 조작  (2) 2024.04.27
백준 31741 - 구간 덮기  (0) 2024.04.21
백준 1129 - 키  (0) 2024.04.12
백준 13573 - 동전 뒤집기 3  (1) 2024.03.23
SOS dp  (0) 2024.03.21