Knapsack and Queries
Time limit10sMemory limit1024 MB
After each add or remove of the lightest cookie, find the max value of a subset whose weight sum mod MOD lies in [l, r], or -1.
- Level
Hard8 of 10
- Topics
- Dynamic programming, Queue
- Solved
- No attempts yet
Problem
You are given a positive integer first. The knapsack is empty at the start.
You perform queries. In each query, you first perform either an ADD or a REMOVE operation, and then a FIND operation.
For ADD, you are given positive integers and . Put a cookie with weight and value into the knapsack.
For REMOVE, take out the cookie with the smallest weight from the knapsack and eat it.
After each ADD or REMOVE, perform FIND. You are given positive integers and . Determine whether you can choose cookies from the knapsack so that , where is the sum of the weights of the chosen cookies. If you cannot, print -1. Otherwise, print the maximum possible sum of the values of the chosen cookies.
Input
The input is given in the following format.
The queries are encrypted as described below. Decrypt to get .
You may assume and . is an ADD+FIND query, and is a REMOVE+FIND query, in which case . Each cookie given by ADD is heavier than any cookie added by a previous ADD. When REMOVE runs, the knapsack is not empty.
The decryption works as follows.
- Create an instance of the class Crypto.
- For each query, call decode in the order . The return values are . Then perform the query and call query with the FIND result.
The code for the Crypto class and usage examples are provided for C++11 (or later), Java, D, and C#. The C++ example is below.
#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];
}
};
The Crypto class takes about 200 to process .
The sample main code is below.
#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);
}
}
Output
For each query, print the result of the FIND operation.
Constraints
, , .
Hints
The result of decoding Sample 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
The result of decoding Sample 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