#include <iostream> #include "message.h" #include "kanapka.h" using namespace std; /* max_long_long ~=2^63 10^3 < 2^10 max_n = 5 * 10^8 max_taste = 10^9 max_sum = 5 * 10^8 * 10^9 = 5 * 10^17 < 10^18 = 10^(3*6) < 2^(10*6) = 2^60 < max_long_long each part of sandwich has: S - sum of all pieces L - local maximum from left - Bajtazar eats only from left R - local maximum from right - Bajtazar eats only from right B - local maximum when Bajtazar eats some from left and light part with only one piece with taste T has: S = T L = R = B = max(0, T) for merging two parts 1 (left) and 2 (right) we have: S = S1 + S2 L = max(L1, S1 + L2) R = max(R2, S2 + R1) B = max(L1 + R2, S1 + B2, S2 + B1) B is best result after merging all parts */ struct SandwichPart { long long sum; long long left; long long right; long long both; }; long long max(long long v1, long long v2) { if (v1 > v2) { return v1; } return v2; } SandwichPart mergeParts(SandwichPart one, SandwichPart two) { SandwichPart result; result.sum = one.sum + two.sum; result.left = max(one.left, one.sum + two.left); result.right = max(two.right, two.sum + one.right); result.both = max(one.left + two.right, max(one.sum + two.both, two.sum + one.both)); return result; } SandwichPart calculatePart(long long start, long long size, bool regularSize) { SandwichPart result; if (size == 1) { long long taste = GetTaste(start); result.sum = taste; long long goodTaste = max(0, taste); result.left = goodTaste; result.right = goodTaste; result.both = goodTaste; return result; } SandwichPart one, two; if (regularSize) { long long halfSize = size / 2; one = calculatePart(start, halfSize, true); two = calculatePart(start + halfSize, halfSize, true); } else { long long oneSize = 1; while (oneSize < size) { oneSize = oneSize * 2; } oneSize = oneSize / 2; one = calculatePart(start, oneSize, true); two = calculatePart(start + oneSize, size - oneSize, false); } result = mergeParts(one, two); return result; } int main() { /* Node 0 is master. Other nodes are slave. Every slave wait for two numbers (start, size) and do: * calculatePart(start, size), * send (sum, left, right, both) to master, * finish work. If slave receive (0, 0) imediately finish work. If N < 100 * NumberOfNodes only master resolve problem. Master send to slaves two numbers (0,0) and resolve all. If N is bigger master divide problem for all nodes and send to slaves (start, size). Later resolve one part and wait for responses from slaves. Finaly merge results. */ if (MyNodeId() == 0) { int numberOfNodes = NumberOfNodes(); int lastNode = numberOfNodes - 1; long long n = GetN(); if (n < 100 * numberOfNodes) { for (int i = 1; i < numberOfNodes; i++) { PutLL(i, 0); PutLL(i, 0); Send(i); } SandwichPart result; result = calculatePart(0, n, false); cout << result.both; } else { long long size = n / numberOfNodes; long long start = size; for (int i = 1; i < lastNode; i++) { PutLL(i, start); PutLL(i, size); Send(i); start = start + size; } PutLL(lastNode, start); PutLL(lastNode, n - start); Send(lastNode); SandwichPart result; result = calculatePart(0, size, false); SandwichPart newPart; for (int i = 1; i < numberOfNodes; i++) { Receive(i); newPart.sum = GetLL(i); newPart.left = GetLL(i); newPart.right = GetLL(i); newPart.both = GetLL(i); result = mergeParts(result, newPart); } cout << result.both; } } else { Receive(0); long long start = GetLL(0); long long size = GetLL(0); if (size > 0) { SandwichPart result; result = calculatePart(start, size, false); PutLL(0, result.sum); PutLL(0, result.left); PutLL(0, result.right); PutLL(0, result.both); Send(0); } } return 0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | #include <iostream> #include "message.h" #include "kanapka.h" using namespace std; /* max_long_long ~=2^63 10^3 < 2^10 max_n = 5 * 10^8 max_taste = 10^9 max_sum = 5 * 10^8 * 10^9 = 5 * 10^17 < 10^18 = 10^(3*6) < 2^(10*6) = 2^60 < max_long_long each part of sandwich has: S - sum of all pieces L - local maximum from left - Bajtazar eats only from left R - local maximum from right - Bajtazar eats only from right B - local maximum when Bajtazar eats some from left and light part with only one piece with taste T has: S = T L = R = B = max(0, T) for merging two parts 1 (left) and 2 (right) we have: S = S1 + S2 L = max(L1, S1 + L2) R = max(R2, S2 + R1) B = max(L1 + R2, S1 + B2, S2 + B1) B is best result after merging all parts */ struct SandwichPart { long long sum; long long left; long long right; long long both; }; long long max(long long v1, long long v2) { if (v1 > v2) { return v1; } return v2; } SandwichPart mergeParts(SandwichPart one, SandwichPart two) { SandwichPart result; result.sum = one.sum + two.sum; result.left = max(one.left, one.sum + two.left); result.right = max(two.right, two.sum + one.right); result.both = max(one.left + two.right, max(one.sum + two.both, two.sum + one.both)); return result; } SandwichPart calculatePart(long long start, long long size, bool regularSize) { SandwichPart result; if (size == 1) { long long taste = GetTaste(start); result.sum = taste; long long goodTaste = max(0, taste); result.left = goodTaste; result.right = goodTaste; result.both = goodTaste; return result; } SandwichPart one, two; if (regularSize) { long long halfSize = size / 2; one = calculatePart(start, halfSize, true); two = calculatePart(start + halfSize, halfSize, true); } else { long long oneSize = 1; while (oneSize < size) { oneSize = oneSize * 2; } oneSize = oneSize / 2; one = calculatePart(start, oneSize, true); two = calculatePart(start + oneSize, size - oneSize, false); } result = mergeParts(one, two); return result; } int main() { /* Node 0 is master. Other nodes are slave. Every slave wait for two numbers (start, size) and do: * calculatePart(start, size), * send (sum, left, right, both) to master, * finish work. If slave receive (0, 0) imediately finish work. If N < 100 * NumberOfNodes only master resolve problem. Master send to slaves two numbers (0,0) and resolve all. If N is bigger master divide problem for all nodes and send to slaves (start, size). Later resolve one part and wait for responses from slaves. Finaly merge results. */ if (MyNodeId() == 0) { int numberOfNodes = NumberOfNodes(); int lastNode = numberOfNodes - 1; long long n = GetN(); if (n < 100 * numberOfNodes) { for (int i = 1; i < numberOfNodes; i++) { PutLL(i, 0); PutLL(i, 0); Send(i); } SandwichPart result; result = calculatePart(0, n, false); cout << result.both; } else { long long size = n / numberOfNodes; long long start = size; for (int i = 1; i < lastNode; i++) { PutLL(i, start); PutLL(i, size); Send(i); start = start + size; } PutLL(lastNode, start); PutLL(lastNode, n - start); Send(lastNode); SandwichPart result; result = calculatePart(0, size, false); SandwichPart newPart; for (int i = 1; i < numberOfNodes; i++) { Receive(i); newPart.sum = GetLL(i); newPart.left = GetLL(i); newPart.right = GetLL(i); newPart.both = GetLL(i); result = mergeParts(result, newPart); } cout << result.both; } } else { Receive(0); long long start = GetLL(0); long long size = GetLL(0); if (size > 0) { SandwichPart result; result = calculatePart(start, size, false); PutLL(0, result.sum); PutLL(0, result.left); PutLL(0, result.right); PutLL(0, result.both); Send(0); } } return 0; } |