만드는 중입니다

아직 만드는 중이라 바뀔 수 있습니다

배낭과 쿼리

시간 제한10초메모리 제한1024 MB

요약
쿠키를 넣거나 가장 가벼운 쿠키를 꺼낼 때마다, 무게 합을 MOD로 나눈 나머지가 [l, r]에 드는 부분집합의 최대 가치를 구합니다. 가능한 경우가 없으면 -1을 출력합니다.
난이도

어려움10점 중 8점

유형
동적 계획법, 큐
정답자
아직 제출이 없습니다

문제

먼저 양의 정수 MODMOD가 주어진다. 처음에 배낭은 비어 있다.

QQ개의 쿼리를 처리한다. 각 쿼리에서는 먼저 ADD 또는 REMOVE 연산 중 하나를 수행하고, 그다음 FIND 연산을 수행한다.

ADD 연산에서는 양의 정수 ww와 vv가 주어진다. 무게가 ww이고 가치가 vv인 쿠키를 배낭에 넣는다.

REMOVE 연산에서는 배낭에 있는 쿠키 중 무게가 가장 작은 쿠키를 꺼내 먹는다.

ADD 또는 REMOVE 연산 후에는 FIND 연산을 수행한다. 양의 정수 ll과 rr이 주어지면, 배낭에서 쿠키를 골라 l≤(X mod MOD)≤rl \leq (X \bmod MOD) \leq r을 만족하게 할 수 있는지 묻는다. 여기서 XX는 고른 쿠키들의 무게 합이다. 만족하게 할 수 없으면 -1을 출력한다. 만족하게 할 수 있으면 고른 쿠키들의 가치 합의 최댓값을 출력한다.

입력

입력은 다음 형식으로 주어진다.

MODMOD QQ t1′t'_1 w1′w'_1 v1′v'_1 l1′l'_1 r1′r'_1 t2′t'_2 w2′w'_2 v2′v'_2 l2′l'_2 r2′r'_2 …\ldots tQ′t'_Q wQ′w'_Q vQ′v'_Q lQ′l'_Q rQ′r'_Q

쿼리는 암호화되어 있으며, 아래 방식으로 복호화한다. ti′,wi′,vi′,li′,ri′t'_i, w'_i, v'_i, l'_i, r'_i를 복호화하면 ti,wi,vi,li,rit_i, w_i, v_i, l_i, r_i를 얻는다.

1≤wi,vi≤1091 \leq w_i, v_i \leq 10^9, 0≤li≤ri≤MOD−10 \leq l_i \leq r_i \leq MOD-1이다. ti=1t_i=1은 ADD+FIND 쿼리이고, ti=2t_i=2는 REMOVE+FIND 쿼리이며 이때 wi=vi=0w_i=v_i=0이다. ADD로 넣는 쿠키는 이전 ADD로 넣은 어떤 쿠키보다도 무겁다. REMOVE를 실행할 때 배낭은 비어 있지 않다.

복호화 과정은 다음과 같다.

  • 먼저 Crypto 클래스의 인스턴스를 만든다.
  • 각 쿼리마다 t′,w′,v′,l′,r′t', w', v', l', r' 순서로 decode 함수를 호출한다. 반환값이 각각 t,w,v,l,rt, w, v, l, r이다. 그다음 쿼리를 수행하고, FIND 결과를 인자로 query 함수를 호출한다.

Crypto 클래스의 코드와 사용 예시는 C++11 이상, Java, D, C#용으로 제공된다. 아래는 C++ 예시이다.

#include <cstdint> //uint8_t, uint32_t

class Crypto {
public:
    Crypto() {
        sm = cnt = 0;
        seed();
    }

    int decode(int z) {
        z ^= next();
        z ^= (next() << 8);
        z ^= (next() << 16);
        z ^= (next() << 22);
        return z;
    }

    void query(long long z) {
        const long long B = 425481007;
        const long long MD = 1000000007;
        cnt++;
        sm = ((sm * B % MD + z) % MD + MD) % MD;
        seed();
    }
private:
    long long sm;
    int cnt;

    uint8_t data[256];
    int I, J;

    void swap_data(int i, int j) {
        uint8_t tmp = data[i];
        data[i] = data[j];
        data[j] = tmp;
    }

    void seed() {
        uint8_t key[8];
        for (int i = 0; i < 4; i++) {
            key[i] = (sm >> (i * 8));
        }
        for (int i = 0; i < 4; i++) {
            key[i+4] = (cnt >> (i * 8));
        }

        for (int i = 0; i < 256; i++) {
            data[i] = i;
        }
        I = J = 0;

        int j = 0;
        for (int i = 0; i < 256; i++) {
            j = (j + data[i] + key[i%8]) % 256;
            swap_data(i, j);
        }
    }

    uint8_t next() {
        I = (I+1) % 256;
        J = (J + data[I]) % 256;
        swap_data(I, J);
        return data[(data[I] + data[J]) % 256];
    }
};

Crypto 클래스는 Q=100000Q = 100000을 처리하는 데 약 200 정도 걸린다.

샘플 main 코드는 다음과 같다.

#include <cstdio>
#include <cstdlib>
#include <cstdint> //uint8_t, uint32_t

class Crypto {
    ...
};

int main() {
    int MOD, Q;
    scanf("%d %d", &MOD, &Q);
    Crypto c;
    for (int i = 0; i < Q; i++) {
        int t, w, v, l, r;
        scanf("%d %d %d %d %d", &t, &w, &v, &l, &r);
        t = c.decode(t);
        w = c.decode(w);
        v = c.decode(v);
        l = c.decode(l);
        r = c.decode(r);
        if (t == 1) {
            (add candy(w, v))
        } else {
            (delete candy)
        }
        long long ans = (answer for query(l, r));
        c.query(ans);
        printf("%lld\n", ans);
    }
}

출력

각 쿼리마다 FIND 연산의 결과를 출력한다.

제한

0≤ti′,wi′,vi′,li′,ri′≤230−10 \leq t'_i, w'_i, v'_i, l'_i, r'_i \leq 2^{30} - 1, 2≤MOD≤5002 \leq MOD \leq 500, 1≤Q≤1000001 \leq Q \leq 100000.

힌트

예제 1을 복호화한 결과:

10
7
1 5 10 5 5
2 0 0 0 9
1 7 10 2 4
1 12 11 9 9
2 0 0 1 1
1 22 10 2 3
1 32 100 4 4

예제 2를 복호화한 결과:

7
20
1 5 44 0 1
1 11 90 0 3
2 0 0 3 4
1 18 68 1 6
1 25 32 2 3
1 31 22 2 3
1 32 26 1 5
1 36 31 3 6
2 0 0 2 5
1 43 10 3 6
2 0 0 5 6
2 0 0 3 4
2 0 0 2 4
2 0 0 1 5
2 0 0 3 5
1 49 48 0 4
2 0 0 1 5
1 50 36 0 6
1 56 48 3 5
1 59 17 3 5

예제2

  1. 예제 1

    입력
    10
    7
    281614559 249378726 433981056 466775634 683612866
    727071329 787572584 591471796 328464426 757737734
    279580343 240336097 538846427 808491898 224313807
    222498984 42804452 371605808 667115067 791865961
    68683864 1045549765 515479514 1067782238 349547144
    907343711 381772625 149003422 879314974 953881571
    883899098 700164610 414212891 752949213 972845634
    
    예상 출력
    10
    0
    -1
    21
    -1
    11
    111
    
  2. 예제 2

    입력
    7
    20
    281614559 249378726 433981094 466775639 683612870
    59536386 999828879 241246766 434670565 174365647
    172060134 848462699 857413429 182122460 807914643
    808426426 600772095 829463884 974102196 354283529
    370037909 1024921880 664216868 194331103 140834169
    917331875 242953442 205247688 335469789 1055568137
    823475244 641321246 617915164 160300810 1073617378
    892669150 939175632 904628449 606339993 1059849410
    829170894 436718235 288920513 228195002 55212938
    772189413 373108543 94133155 610930061 513937768
    986619331 175674265 812546186 865335970 605634588
    880196843 1071068047 723408215 587598264 380801783
    393196081 141080294 584230885 135343295 661927186
    5740819 967233824 22597607 888639499 467454437
    365679801 515258603 989059385 962028117 761163096
    357270919 737051059 569528959 935653628 70506031
    869282414 947492121 280522456 96822010 856514221
    155948699 826430734 291243254 381421299 617876780
    980891674 833928389 1048677341 522527723 223764850
    50617939 963598173 281959650 499436870 47455938
    
    예상 출력
    0
    134
    90
    158
    -1
    22
    238
    269
    179
    189
    121
    53
    41
    41
    -1
    58
    -1
    84
    -1
    149