/*
Problem: Minimum Cost to Satisfy Daily Demand Using Buy and Repair Options
Company Tag: Walmart
Problem Statement:
A factory works for N days.
On day i, it needs exactly R[i] widgets.
A widget can be obtained in three ways:
1. Buy a new widget
Cost = P
2. Send a used widget for quick repair
It returns after M days
Cost = F
3. Send a used widget for slow repair
It returns after Q days
Cost = S
We need to satisfy demand every day with minimum total cost.
Constraints:
1 <= N <= 2000
1 <= R[i] <= 10^7
1 <= P, M, F, Q, S <= 10^4
Q > M
Simple Brute Force:
For every day, try all choices:
buy new,
quick repair,
slow repair,
store,
discard.
Why Brute Force Fails:
The number of possible schedules becomes huge.
Better Idea:
Model this as a minimum cost flow problem.
Each widget is one unit of flow.
For each day:
- clean widgets are used to satisfy demand
- after use, they become dirty
- dirty widgets can be repaired and reused later
- new widgets can be bought when needed
We force exactly R[i] widgets to be used on day i.
Dry Run:
N = 3
R = [1, 1, 1]
P = 10
M = 1, F = 3
Q = 2, S = 1
Best plan:
Day 1: buy 1 widget cost 10
Day 2: quick repaired one cost 3
Day 3: quick repaired one cost 3
Total cost = 16
Time Complexity:
Around O(flow augmentations * E log V)
Space Complexity:
O(N)
*/
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int to;
int reverseIndex;
long long capacity;
long long cost;
};
class MinCostFlow {
public:
int nodeCount;
vector<vector<Edge>> graph;
MinCostFlow(int n) {
nodeCount = n;
graph.assign(n, {});
}
void addEdge(int from, int to, long long capacity, long long cost) {
Edge forward = {to, (int)graph[to].size(), capacity, cost};
Edge backward = {from, (int)graph[from].size(), 0, -cost};
graph[from].push_back(forward);
graph[to].push_back(backward);
}
pair<long long, long long> minCostMaxFlow(int source, int sink, long long requiredFlow) {
const long long INF = (1LL << 60);
long long totalFlow = 0;
long long totalCost = 0;
vector<long long> potential(nodeCount, 0);
while (totalFlow < requiredFlow) {
vector<long long> distance(nodeCount, INF);
vector<int> parentNode(nodeCount, -1);
vector<int> parentEdge(nodeCount, -1);
priority_queue<
pair<long long, int>,
vector<pair<long long, int>>,
greater<pair<long long, int>>
> pq;
distance[source] = 0;
pq.push({0, source});
while (!pq.empty()) {
pair<long long, int> current = pq.top();
pq.pop();
long long currentDistance = current.first;
int node = current.second;
if (currentDistance != distance[node]) {
continue;
}
for (int i = 0; i < (int)graph[node].size(); i++) {
Edge &edge = graph[node][i];
if (edge.capacity <= 0) {
continue;
}
long long newDistance =
distance[node] + edge.cost + potential[node] - potential[edge.to];
if (newDistance < distance[edge.to]) {
distance[edge.to] = newDistance;
parentNode[edge.to] = node;
parentEdge[edge.to] = i;
pq.push({newDistance, edge.to});
}
}
}
if (distance[sink] == INF) {
break;
}
for (int i = 0; i < nodeCount; i++) {
if (distance[i] < INF) {
potential[i] += distance[i];
}
}
long long addFlow = requiredFlow - totalFlow;
int node = sink;
while (node != source) {
int previous = parentNode[node];
int edgeIndex = parentEdge[node];
addFlow = min(addFlow, graph[previous][edgeIndex].capacity);
node = previous;
}
node = sink;
while (node != source) {
int previous = parentNode[node];
int edgeIndex = parentEdge[node];
Edge &edge = graph[previous][edgeIndex];
edge.capacity -= addFlow;
graph[node][edge.reverseIndex].capacity += addFlow;
totalCost += addFlow * edge.cost;
node = previous;
}
totalFlow += addFlow;
}
return {totalFlow, totalCost};
}
};
int main() {
int N;
cin >> N;
vector<long long> R(N);
for (int i = 0; i < N; i++) {
cin >> R[i];
}
long long P, M, F, Q, S;
cin >> P >> M >> F >> Q >> S;
const long long INF_CAP = (1LL << 55);
int cleanStart = 0;
int dirtyStart = N;
int source = 2 * N;
int sink = 2 * N + 1;
int superSource = 2 * N + 2;
int superSink = 2 * N + 3;
int totalNodes = 2 * N + 4;
MinCostFlow flow(totalNodes);
vector<long long> balance(totalNodes, 0);
auto addLowerBoundEdge = [&](int from, int to, long long lower, long long upper, long long cost) {
/*
Lower bound trick:
We force at least 'lower' flow through this edge
by adjusting the balance of both endpoints.
*/
flow.addEdge(from, to, upper - lower, cost);
balance[from] -= lower;
balance[to] += lower;
};
for (int day = 0; day < N; day++) {
int cleanNode = cleanStart + day;
int dirtyNode = dirtyStart + day;
// Buy a new clean widget for this day.
addLowerBoundEdge(source, cleanNode, 0, INF_CAP, P);
// Exactly R[day] widgets must be used on this day.
addLowerBoundEdge(cleanNode, dirtyNode, R[day], R[day], 0);
// After use, we may discard the dirty widget.
addLowerBoundEdge(dirtyNode, sink, 0, INF_CAP, 0);
// Clean widgets can be stored for the next day.
if (day + 1 < N) {
addLowerBoundEdge(cleanNode, cleanStart + day + 1, 0, INF_CAP, 0);
}
// Dirty widgets can also be kept and repaired later.
if (day + 1 < N) {
addLowerBoundEdge(dirtyNode, dirtyStart + day + 1, 0, INF_CAP, 0);
}
// Quick repair makes a dirty widget clean after M days.
if (day + M < N) {
addLowerBoundEdge(dirtyNode, cleanStart + day + M, 0, INF_CAP, F);
}
// Slow repair makes a dirty widget clean after Q days.
if (day + Q < N) {
addLowerBoundEdge(dirtyNode, cleanStart + day + Q, 0, INF_CAP, S);
}
}
/*
This edge converts the network into a circulation problem.
It lets the flow balance out properly.
*/
addLowerBoundEdge(sink, source, 0, INF_CAP, 0);
long long requiredFlow = 0;
for (int i = 0; i < totalNodes; i++) {
if (balance[i] > 0) {
flow.addEdge(superSource, i, balance[i], 0);
requiredFlow += balance[i];
} else if (balance[i] < 0) {
flow.addEdge(i, superSink, -balance[i], 0);
}
}
pair<long long, long long> result =
flow.minCostMaxFlow(superSource, superSink, requiredFlow);
cout << result.second << endl;
return 0;
}
LyoKICAgIFByb2JsZW06IE1pbmltdW0gQ29zdCB0byBTYXRpc2Z5IERhaWx5IERlbWFuZCBVc2luZyBCdXkgYW5kIFJlcGFpciBPcHRpb25zCiAgICBDb21wYW55IFRhZzogV2FsbWFydAoKICAgIFByb2JsZW0gU3RhdGVtZW50OgogICAgICAgIEEgZmFjdG9yeSB3b3JrcyBmb3IgTiBkYXlzLgoKICAgICAgICBPbiBkYXkgaSwgaXQgbmVlZHMgZXhhY3RseSBSW2ldIHdpZGdldHMuCgogICAgICAgIEEgd2lkZ2V0IGNhbiBiZSBvYnRhaW5lZCBpbiB0aHJlZSB3YXlzOgoKICAgICAgICAgICAgMS4gQnV5IGEgbmV3IHdpZGdldAogICAgICAgICAgICAgICBDb3N0ID0gUAoKICAgICAgICAgICAgMi4gU2VuZCBhIHVzZWQgd2lkZ2V0IGZvciBxdWljayByZXBhaXIKICAgICAgICAgICAgICAgSXQgcmV0dXJucyBhZnRlciBNIGRheXMKICAgICAgICAgICAgICAgQ29zdCA9IEYKCiAgICAgICAgICAgIDMuIFNlbmQgYSB1c2VkIHdpZGdldCBmb3Igc2xvdyByZXBhaXIKICAgICAgICAgICAgICAgSXQgcmV0dXJucyBhZnRlciBRIGRheXMKICAgICAgICAgICAgICAgQ29zdCA9IFMKCiAgICAgICAgV2UgbmVlZCB0byBzYXRpc2Z5IGRlbWFuZCBldmVyeSBkYXkgd2l0aCBtaW5pbXVtIHRvdGFsIGNvc3QuCgogICAgQ29uc3RyYWludHM6CiAgICAgICAgMSA8PSBOIDw9IDIwMDAKICAgICAgICAxIDw9IFJbaV0gPD0gMTBeNwogICAgICAgIDEgPD0gUCwgTSwgRiwgUSwgUyA8PSAxMF40CiAgICAgICAgUSA+IE0KCiAgICBTaW1wbGUgQnJ1dGUgRm9yY2U6CiAgICAgICAgRm9yIGV2ZXJ5IGRheSwgdHJ5IGFsbCBjaG9pY2VzOgogICAgICAgICAgICBidXkgbmV3LAogICAgICAgICAgICBxdWljayByZXBhaXIsCiAgICAgICAgICAgIHNsb3cgcmVwYWlyLAogICAgICAgICAgICBzdG9yZSwKICAgICAgICAgICAgZGlzY2FyZC4KCiAgICBXaHkgQnJ1dGUgRm9yY2UgRmFpbHM6CiAgICAgICAgVGhlIG51bWJlciBvZiBwb3NzaWJsZSBzY2hlZHVsZXMgYmVjb21lcyBodWdlLgoKICAgIEJldHRlciBJZGVhOgogICAgICAgIE1vZGVsIHRoaXMgYXMgYSBtaW5pbXVtIGNvc3QgZmxvdyBwcm9ibGVtLgoKICAgICAgICBFYWNoIHdpZGdldCBpcyBvbmUgdW5pdCBvZiBmbG93LgoKICAgICAgICBGb3IgZWFjaCBkYXk6CiAgICAgICAgICAgIC0gY2xlYW4gd2lkZ2V0cyBhcmUgdXNlZCB0byBzYXRpc2Z5IGRlbWFuZAogICAgICAgICAgICAtIGFmdGVyIHVzZSwgdGhleSBiZWNvbWUgZGlydHkKICAgICAgICAgICAgLSBkaXJ0eSB3aWRnZXRzIGNhbiBiZSByZXBhaXJlZCBhbmQgcmV1c2VkIGxhdGVyCiAgICAgICAgICAgIC0gbmV3IHdpZGdldHMgY2FuIGJlIGJvdWdodCB3aGVuIG5lZWRlZAoKICAgICAgICBXZSBmb3JjZSBleGFjdGx5IFJbaV0gd2lkZ2V0cyB0byBiZSB1c2VkIG9uIGRheSBpLgoKICAgIERyeSBSdW46CiAgICAgICAgTiA9IDMKICAgICAgICBSID0gWzEsIDEsIDFdCiAgICAgICAgUCA9IDEwCiAgICAgICAgTSA9IDEsIEYgPSAzCiAgICAgICAgUSA9IDIsIFMgPSAxCgogICAgICAgIEJlc3QgcGxhbjoKICAgICAgICAgICAgRGF5IDE6IGJ1eSAxIHdpZGdldCAgICAgICAgY29zdCAxMAogICAgICAgICAgICBEYXkgMjogcXVpY2sgcmVwYWlyZWQgb25lICBjb3N0IDMKICAgICAgICAgICAgRGF5IDM6IHF1aWNrIHJlcGFpcmVkIG9uZSAgY29zdCAzCgogICAgICAgIFRvdGFsIGNvc3QgPSAxNgoKICAgIFRpbWUgQ29tcGxleGl0eToKICAgICAgICBBcm91bmQgTyhmbG93IGF1Z21lbnRhdGlvbnMgKiBFIGxvZyBWKQoKICAgIFNwYWNlIENvbXBsZXhpdHk6CiAgICAgICAgTyhOKQoqLwoKI2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CgpzdHJ1Y3QgRWRnZSB7CiAgICBpbnQgdG87CiAgICBpbnQgcmV2ZXJzZUluZGV4OwogICAgbG9uZyBsb25nIGNhcGFjaXR5OwogICAgbG9uZyBsb25nIGNvc3Q7Cn07CgpjbGFzcyBNaW5Db3N0RmxvdyB7CnB1YmxpYzoKICAgIGludCBub2RlQ291bnQ7CiAgICB2ZWN0b3I8dmVjdG9yPEVkZ2U+PiBncmFwaDsKCiAgICBNaW5Db3N0RmxvdyhpbnQgbikgewogICAgICAgIG5vZGVDb3VudCA9IG47CiAgICAgICAgZ3JhcGguYXNzaWduKG4sIHt9KTsKICAgIH0KCiAgICB2b2lkIGFkZEVkZ2UoaW50IGZyb20sIGludCB0bywgbG9uZyBsb25nIGNhcGFjaXR5LCBsb25nIGxvbmcgY29zdCkgewogICAgICAgIEVkZ2UgZm9yd2FyZCA9IHt0bywgKGludClncmFwaFt0b10uc2l6ZSgpLCBjYXBhY2l0eSwgY29zdH07CiAgICAgICAgRWRnZSBiYWNrd2FyZCA9IHtmcm9tLCAoaW50KWdyYXBoW2Zyb21dLnNpemUoKSwgMCwgLWNvc3R9OwoKICAgICAgICBncmFwaFtmcm9tXS5wdXNoX2JhY2soZm9yd2FyZCk7CiAgICAgICAgZ3JhcGhbdG9dLnB1c2hfYmFjayhiYWNrd2FyZCk7CiAgICB9CgogICAgcGFpcjxsb25nIGxvbmcsIGxvbmcgbG9uZz4gbWluQ29zdE1heEZsb3coaW50IHNvdXJjZSwgaW50IHNpbmssIGxvbmcgbG9uZyByZXF1aXJlZEZsb3cpIHsKICAgICAgICBjb25zdCBsb25nIGxvbmcgSU5GID0gKDFMTCA8PCA2MCk7CgogICAgICAgIGxvbmcgbG9uZyB0b3RhbEZsb3cgPSAwOwogICAgICAgIGxvbmcgbG9uZyB0b3RhbENvc3QgPSAwOwoKICAgICAgICB2ZWN0b3I8bG9uZyBsb25nPiBwb3RlbnRpYWwobm9kZUNvdW50LCAwKTsKCiAgICAgICAgd2hpbGUgKHRvdGFsRmxvdyA8IHJlcXVpcmVkRmxvdykgewogICAgICAgICAgICB2ZWN0b3I8bG9uZyBsb25nPiBkaXN0YW5jZShub2RlQ291bnQsIElORik7CiAgICAgICAgICAgIHZlY3RvcjxpbnQ+IHBhcmVudE5vZGUobm9kZUNvdW50LCAtMSk7CiAgICAgICAgICAgIHZlY3RvcjxpbnQ+IHBhcmVudEVkZ2Uobm9kZUNvdW50LCAtMSk7CgogICAgICAgICAgICBwcmlvcml0eV9xdWV1ZTwKICAgICAgICAgICAgICAgIHBhaXI8bG9uZyBsb25nLCBpbnQ+LAogICAgICAgICAgICAgICAgdmVjdG9yPHBhaXI8bG9uZyBsb25nLCBpbnQ+PiwKICAgICAgICAgICAgICAgIGdyZWF0ZXI8cGFpcjxsb25nIGxvbmcsIGludD4+CiAgICAgICAgICAgID4gcHE7CgogICAgICAgICAgICBkaXN0YW5jZVtzb3VyY2VdID0gMDsKICAgICAgICAgICAgcHEucHVzaCh7MCwgc291cmNlfSk7CgogICAgICAgICAgICB3aGlsZSAoIXBxLmVtcHR5KCkpIHsKICAgICAgICAgICAgICAgIHBhaXI8bG9uZyBsb25nLCBpbnQ+IGN1cnJlbnQgPSBwcS50b3AoKTsKICAgICAgICAgICAgICAgIHBxLnBvcCgpOwoKICAgICAgICAgICAgICAgIGxvbmcgbG9uZyBjdXJyZW50RGlzdGFuY2UgPSBjdXJyZW50LmZpcnN0OwogICAgICAgICAgICAgICAgaW50IG5vZGUgPSBjdXJyZW50LnNlY29uZDsKCiAgICAgICAgICAgICAgICBpZiAoY3VycmVudERpc3RhbmNlICE9IGRpc3RhbmNlW25vZGVdKSB7CiAgICAgICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCAoaW50KWdyYXBoW25vZGVdLnNpemUoKTsgaSsrKSB7CiAgICAgICAgICAgICAgICAgICAgRWRnZSAmZWRnZSA9IGdyYXBoW25vZGVdW2ldOwoKICAgICAgICAgICAgICAgICAgICBpZiAoZWRnZS5jYXBhY2l0eSA8PSAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgbG9uZyBsb25nIG5ld0Rpc3RhbmNlID0KICAgICAgICAgICAgICAgICAgICAgICAgZGlzdGFuY2Vbbm9kZV0gKyBlZGdlLmNvc3QgKyBwb3RlbnRpYWxbbm9kZV0gLSBwb3RlbnRpYWxbZWRnZS50b107CgogICAgICAgICAgICAgICAgICAgIGlmIChuZXdEaXN0YW5jZSA8IGRpc3RhbmNlW2VkZ2UudG9dKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3RhbmNlW2VkZ2UudG9dID0gbmV3RGlzdGFuY2U7CiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmVudE5vZGVbZWRnZS50b10gPSBub2RlOwogICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRFZGdlW2VkZ2UudG9dID0gaTsKICAgICAgICAgICAgICAgICAgICAgICAgcHEucHVzaCh7bmV3RGlzdGFuY2UsIGVkZ2UudG99KTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGlmIChkaXN0YW5jZVtzaW5rXSA9PSBJTkYpIHsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CgogICAgICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IG5vZGVDb3VudDsgaSsrKSB7CiAgICAgICAgICAgICAgICBpZiAoZGlzdGFuY2VbaV0gPCBJTkYpIHsKICAgICAgICAgICAgICAgICAgICBwb3RlbnRpYWxbaV0gKz0gZGlzdGFuY2VbaV07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxvbmcgbG9uZyBhZGRGbG93ID0gcmVxdWlyZWRGbG93IC0gdG90YWxGbG93OwogICAgICAgICAgICBpbnQgbm9kZSA9IHNpbms7CgogICAgICAgICAgICB3aGlsZSAobm9kZSAhPSBzb3VyY2UpIHsKICAgICAgICAgICAgICAgIGludCBwcmV2aW91cyA9IHBhcmVudE5vZGVbbm9kZV07CiAgICAgICAgICAgICAgICBpbnQgZWRnZUluZGV4ID0gcGFyZW50RWRnZVtub2RlXTsKCiAgICAgICAgICAgICAgICBhZGRGbG93ID0gbWluKGFkZEZsb3csIGdyYXBoW3ByZXZpb3VzXVtlZGdlSW5kZXhdLmNhcGFjaXR5KTsKICAgICAgICAgICAgICAgIG5vZGUgPSBwcmV2aW91czsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbm9kZSA9IHNpbms7CgogICAgICAgICAgICB3aGlsZSAobm9kZSAhPSBzb3VyY2UpIHsKICAgICAgICAgICAgICAgIGludCBwcmV2aW91cyA9IHBhcmVudE5vZGVbbm9kZV07CiAgICAgICAgICAgICAgICBpbnQgZWRnZUluZGV4ID0gcGFyZW50RWRnZVtub2RlXTsKCiAgICAgICAgICAgICAgICBFZGdlICZlZGdlID0gZ3JhcGhbcHJldmlvdXNdW2VkZ2VJbmRleF07CgogICAgICAgICAgICAgICAgZWRnZS5jYXBhY2l0eSAtPSBhZGRGbG93OwogICAgICAgICAgICAgICAgZ3JhcGhbbm9kZV1bZWRnZS5yZXZlcnNlSW5kZXhdLmNhcGFjaXR5ICs9IGFkZEZsb3c7CgogICAgICAgICAgICAgICAgdG90YWxDb3N0ICs9IGFkZEZsb3cgKiBlZGdlLmNvc3Q7CgogICAgICAgICAgICAgICAgbm9kZSA9IHByZXZpb3VzOwogICAgICAgICAgICB9CgogICAgICAgICAgICB0b3RhbEZsb3cgKz0gYWRkRmxvdzsKICAgICAgICB9CgogICAgICAgIHJldHVybiB7dG90YWxGbG93LCB0b3RhbENvc3R9OwogICAgfQp9OwoKaW50IG1haW4oKSB7CiAgICBpbnQgTjsKICAgIGNpbiA+PiBOOwoKICAgIHZlY3Rvcjxsb25nIGxvbmc+IFIoTik7CgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBOOyBpKyspIHsKICAgICAgICBjaW4gPj4gUltpXTsKICAgIH0KCiAgICBsb25nIGxvbmcgUCwgTSwgRiwgUSwgUzsKICAgIGNpbiA+PiBQID4+IE0gPj4gRiA+PiBRID4+IFM7CgogICAgY29uc3QgbG9uZyBsb25nIElORl9DQVAgPSAoMUxMIDw8IDU1KTsKCiAgICBpbnQgY2xlYW5TdGFydCA9IDA7CiAgICBpbnQgZGlydHlTdGFydCA9IE47CgogICAgaW50IHNvdXJjZSA9IDIgKiBOOwogICAgaW50IHNpbmsgPSAyICogTiArIDE7CgogICAgaW50IHN1cGVyU291cmNlID0gMiAqIE4gKyAyOwogICAgaW50IHN1cGVyU2luayA9IDIgKiBOICsgMzsKCiAgICBpbnQgdG90YWxOb2RlcyA9IDIgKiBOICsgNDsKCiAgICBNaW5Db3N0RmxvdyBmbG93KHRvdGFsTm9kZXMpOwoKICAgIHZlY3Rvcjxsb25nIGxvbmc+IGJhbGFuY2UodG90YWxOb2RlcywgMCk7CgogICAgYXV0byBhZGRMb3dlckJvdW5kRWRnZSA9IFsmXShpbnQgZnJvbSwgaW50IHRvLCBsb25nIGxvbmcgbG93ZXIsIGxvbmcgbG9uZyB1cHBlciwgbG9uZyBsb25nIGNvc3QpIHsKICAgICAgICAvKgogICAgICAgICAgICBMb3dlciBib3VuZCB0cmljazoKICAgICAgICAgICAgV2UgZm9yY2UgYXQgbGVhc3QgJ2xvd2VyJyBmbG93IHRocm91Z2ggdGhpcyBlZGdlCiAgICAgICAgICAgIGJ5IGFkanVzdGluZyB0aGUgYmFsYW5jZSBvZiBib3RoIGVuZHBvaW50cy4KICAgICAgICAqLwogICAgICAgIGZsb3cuYWRkRWRnZShmcm9tLCB0bywgdXBwZXIgLSBsb3dlciwgY29zdCk7CgogICAgICAgIGJhbGFuY2VbZnJvbV0gLT0gbG93ZXI7CiAgICAgICAgYmFsYW5jZVt0b10gKz0gbG93ZXI7CiAgICB9OwoKICAgIGZvciAoaW50IGRheSA9IDA7IGRheSA8IE47IGRheSsrKSB7CiAgICAgICAgaW50IGNsZWFuTm9kZSA9IGNsZWFuU3RhcnQgKyBkYXk7CiAgICAgICAgaW50IGRpcnR5Tm9kZSA9IGRpcnR5U3RhcnQgKyBkYXk7CgogICAgICAgIC8vIEJ1eSBhIG5ldyBjbGVhbiB3aWRnZXQgZm9yIHRoaXMgZGF5LgogICAgICAgIGFkZExvd2VyQm91bmRFZGdlKHNvdXJjZSwgY2xlYW5Ob2RlLCAwLCBJTkZfQ0FQLCBQKTsKCiAgICAgICAgLy8gRXhhY3RseSBSW2RheV0gd2lkZ2V0cyBtdXN0IGJlIHVzZWQgb24gdGhpcyBkYXkuCiAgICAgICAgYWRkTG93ZXJCb3VuZEVkZ2UoY2xlYW5Ob2RlLCBkaXJ0eU5vZGUsIFJbZGF5XSwgUltkYXldLCAwKTsKCiAgICAgICAgLy8gQWZ0ZXIgdXNlLCB3ZSBtYXkgZGlzY2FyZCB0aGUgZGlydHkgd2lkZ2V0LgogICAgICAgIGFkZExvd2VyQm91bmRFZGdlKGRpcnR5Tm9kZSwgc2luaywgMCwgSU5GX0NBUCwgMCk7CgogICAgICAgIC8vIENsZWFuIHdpZGdldHMgY2FuIGJlIHN0b3JlZCBmb3IgdGhlIG5leHQgZGF5LgogICAgICAgIGlmIChkYXkgKyAxIDwgTikgewogICAgICAgICAgICBhZGRMb3dlckJvdW5kRWRnZShjbGVhbk5vZGUsIGNsZWFuU3RhcnQgKyBkYXkgKyAxLCAwLCBJTkZfQ0FQLCAwKTsKICAgICAgICB9CgogICAgICAgIC8vIERpcnR5IHdpZGdldHMgY2FuIGFsc28gYmUga2VwdCBhbmQgcmVwYWlyZWQgbGF0ZXIuCiAgICAgICAgaWYgKGRheSArIDEgPCBOKSB7CiAgICAgICAgICAgIGFkZExvd2VyQm91bmRFZGdlKGRpcnR5Tm9kZSwgZGlydHlTdGFydCArIGRheSArIDEsIDAsIElORl9DQVAsIDApOwogICAgICAgIH0KCiAgICAgICAgLy8gUXVpY2sgcmVwYWlyIG1ha2VzIGEgZGlydHkgd2lkZ2V0IGNsZWFuIGFmdGVyIE0gZGF5cy4KICAgICAgICBpZiAoZGF5ICsgTSA8IE4pIHsKICAgICAgICAgICAgYWRkTG93ZXJCb3VuZEVkZ2UoZGlydHlOb2RlLCBjbGVhblN0YXJ0ICsgZGF5ICsgTSwgMCwgSU5GX0NBUCwgRik7CiAgICAgICAgfQoKICAgICAgICAvLyBTbG93IHJlcGFpciBtYWtlcyBhIGRpcnR5IHdpZGdldCBjbGVhbiBhZnRlciBRIGRheXMuCiAgICAgICAgaWYgKGRheSArIFEgPCBOKSB7CiAgICAgICAgICAgIGFkZExvd2VyQm91bmRFZGdlKGRpcnR5Tm9kZSwgY2xlYW5TdGFydCArIGRheSArIFEsIDAsIElORl9DQVAsIFMpOwogICAgICAgIH0KICAgIH0KCiAgICAvKgogICAgICAgIFRoaXMgZWRnZSBjb252ZXJ0cyB0aGUgbmV0d29yayBpbnRvIGEgY2lyY3VsYXRpb24gcHJvYmxlbS4KICAgICAgICBJdCBsZXRzIHRoZSBmbG93IGJhbGFuY2Ugb3V0IHByb3Blcmx5LgogICAgKi8KICAgIGFkZExvd2VyQm91bmRFZGdlKHNpbmssIHNvdXJjZSwgMCwgSU5GX0NBUCwgMCk7CgogICAgbG9uZyBsb25nIHJlcXVpcmVkRmxvdyA9IDA7CgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCB0b3RhbE5vZGVzOyBpKyspIHsKICAgICAgICBpZiAoYmFsYW5jZVtpXSA+IDApIHsKICAgICAgICAgICAgZmxvdy5hZGRFZGdlKHN1cGVyU291cmNlLCBpLCBiYWxhbmNlW2ldLCAwKTsKICAgICAgICAgICAgcmVxdWlyZWRGbG93ICs9IGJhbGFuY2VbaV07CiAgICAgICAgfSBlbHNlIGlmIChiYWxhbmNlW2ldIDwgMCkgewogICAgICAgICAgICBmbG93LmFkZEVkZ2UoaSwgc3VwZXJTaW5rLCAtYmFsYW5jZVtpXSwgMCk7CiAgICAgICAgfQogICAgfQoKICAgIHBhaXI8bG9uZyBsb25nLCBsb25nIGxvbmc+IHJlc3VsdCA9CiAgICAgICAgZmxvdy5taW5Db3N0TWF4RmxvdyhzdXBlclNvdXJjZSwgc3VwZXJTaW5rLCByZXF1aXJlZEZsb3cpOwoKICAgIGNvdXQgPDwgcmVzdWx0LnNlY29uZCA8PCBlbmRsOwoKICAgIHJldHVybiAwOwp9