// wieza.cpp : Ten plik zawiera funkcję „main”. W nim rozpoczyna się i kończy wykonywanie programu.
//
#include <iostream>
#include <vector>
#include <algorithm>
const int MAX_N = 500020;
const int MAX_LOG_N = 20;
long long color_max[1 << 21];
long long temp_col[MAX_N + 1];
int pow2[21] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576 };
//long long color_max[MAX_N];
long long access_outer_max(int x, int s, long long *a) { //if S=1 returns 0
long long cur_max = 0;
for (int i = 0; i < s - 1; i++) {
cur_max = std::max(cur_max, a[x ^ 1]);
x = (x >> 1) | (1 << s );
}
return cur_max;
}
void update_single(int x, long long val, int s, long long *a) {
if (a[x] >= val) return; //NO NEED TO UPADTE
a[x] = val;
for (int i = 0; i < s; i++) {
x = (x >> 1) | (1 << s);
if (a[x] >= val) return; // NO NEED FOR FURTHER UPDATE
a[x] = val;
}
}
void update_all(int s, long long *a) {
int x = 0;
int prev_x = 0;
for (int level = s - 1; level >= 0; level--) {
x = (x >> 1) | (1 << s);
for (int i = 0; i < (1 << level); i++) {
a[x | i] = std::max(a[prev_x | (i << 1) | 1], a[prev_x | (i << 1)]);
}
prev_x = x;
}
}
long long access_all_max(int s, long long *a) {
return a[(1 << (s + 1)) - 2];
}
int main()
{
std::vector<std::pair<int, int>> blocks = std::vector<std::pair<int, int>>(); //(SIZE, COLOR)
int n, c;
std::cin >> n;
std::cin >> c;
for (int i = 0; i < (1 << 21); i++) color_max[i] = 0;
for (int i = 0; i < MAX_N + 1; i++) temp_col[i] = 0;
for (int i = 0; i < n; i++) {
int a, w;
std::cin >> a >> w;
blocks.push_back({ a,w });
}
std::sort(begin(blocks), end(blocks), std::less<std::pair<int,int>>());
int cur_size = 0;
int pos = 0;
while (pos < n) {
long long cur_size = blocks[pos].first;
int last_pos = pos;
while (pos < n && blocks[pos].first == cur_size) {
pos++;
}
pos--;
std::vector<int> considered_col = std::vector<int>();
//CALCULATE PROFIT FOR EACH EQUAL SIZED BLOCK
for (int i = last_pos; i <= pos; i++) {
long long tmp = access_outer_max(blocks[i].second, 20, color_max);
long long profit = 0;
if (tmp != 0)
profit = tmp + blocks[i].first - c;
else // THE BEST WAS AS GOOD AS NOT USING ANY BLOCKS ABOVE
profit = blocks[i].first;
profit = std::max(profit, color_max[blocks[i].second] + blocks[i].first);
temp_col[blocks[i].second] = std::max(temp_col[blocks[i].second], profit);
considered_col.push_back( blocks[i].second );
}
// UPDATE THE STORED PROFITS
for (int i = 0; i < considered_col.size(); i++) {
if (temp_col[considered_col[i]] != 0LL) {
update_single(considered_col[i], temp_col[considered_col[i]], 20, color_max);
temp_col[considered_col[i]] = 0;
}
}
std::cout << "";
/*// ŹLE PRZECZYTAŁEM ZADANIE. ROZWIĄZYWAŁEM TRUDNIEJSZY WARIANT WIEŻY, GDZIE DOPUSZAM RÓWNE DŁUGOŚCI KLOCKÓW
block_sec.push_back({ count, prev_color });
std::sort(begin(block_sec), end(block_sec), std::greater<>());
int end_upper = 0;
for (int i = 0; i < block_sec.size(); i++) {
if (block_sec[i].first * cur_size >= c) {
end_upper++;
}
else break;
}
auto tmp = std::upper_bound(std::begin(pow2), std::end(pow2), block_sec.size());
int block_s = std::distance(std::begin(pow2), tmp);
long long upper_profit = 0;
//PRECOMPUTATION
for (int i = 0; i < end_upper; i++) {
//FOR THE PROFITABLE
upper_sec_max[i] = std::max(access_outer_max(block_sec[i].second, 19, color_max) - c,
color_max[block_sec[i].second]); // PROFIT FROM CHOOSING END OF THIS COLOR (LENGTH OF THE BLOCK NOT COUNTED)
upper_profit += block_sec[i].first * cur_size;
}
upper_profit -= (end_upper - 1)*c;
update_all(block_s, upper_sec_max);
for (int i = end_upper; i < block_sec.size(); i++) {
//FOR THE UNPROFITABLE I ADD THE GAIN FROM IT HEIGHT AND MINUS THE ADITIONAL COST;
lower_sec_max[i] = std::max (access_outer_max(block_sec[i].second, 19, color_max) - c, color_max[block_sec[i].second])
+ block_sec[i].first*cur_size - c; //PROFIT FROM CHOOSING END OF THIS COLOR (+ LENGTH OF THE BLOCK AND SWITCHING COST)
}
update_all(block_s, lower_sec_max);
//ADDING THE BLOCKS TO THE TOWER
for (int i = 0; i < end_upper; i++) { //THINK WHAT IF THERE IS ONLY 1 ELEMENT
//FOR THE PROFITABLE START
//SECTION END ON A DIFFERENT COLOR FROM PROFITABLE
long long cur_max = 0;
cur_max = std::max(cur_max, access_outer_max(i, block_s, upper_sec_max) + upper_profit);
//SECTION END ON A COLOR FROM UNPROFITABLE
if (end_upper != block_sec.size())
cur_max = std::max(cur_max, access_all_max(block_s, lower_sec_max) + upper_profit);
//SECTION END IS THE SAME
//NO SPLITTING
cur_max = std::max(cur_max, upper_sec_max[i] + block_sec[i].first*cur_size);
//SEGMENT SPLIT WHAT IF THERE ARE NO OTHER !!!!!!!!!!!!!!!!!!!!!!!!!
if (block_sec[i].first > 1 && end_upper > 1) {
cur_max = std::max(cur_max, upper_sec_max[i] + upper_profit - c*(end_upper > 1));
}
update_single(block_sec[i].second, cur_max, 19, color_max);
}
for (int i = end_upper; i < block_sec.size(); i++) {
//FOR THE UNPROFITABLE START
long long cur_max = 0;
//SECTION END ON A COLOR FROM PROFITABLE
if (end_upper != 0)
cur_max = std::max(cur_max, access_all_max(block_s, upper_sec_max) + upper_profit - c);
//SECTION END ON A DIFFERENT COLOR FROM UNPROFITABLE
cur_max = std::max(cur_max, access_outer_max(i, block_s, lower_sec_max) + block_sec[i].first*cur_size);
//SECTION END IS THE SAME
// NO SPLITTING
cur_max = std::max(cur_max, lower_sec_max[i] + c);
//SEGMENT SPLIT
if (block_sec[i].first > 1 && end_upper > 1) { //upper section not empty and current segment is splittable
cur_max = std::max(cur_max, lower_sec_max[i] + upper_profit - 2*c);
}
update_single(block_sec[i].second, cur_max, 19, color_max);
}
for (int i = 0; i < (1 << (block_s + 1)); i++) upper_sec_max[i] = 0;
for (int i = 0; i < (1 << (block_s + 1) ); i++) lower_sec_max[i] = 0;
*/
pos++;
}
std::cout << access_all_max(20, color_max);
}
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 180 181 182 183 | // wieza.cpp : Ten plik zawiera funkcję „main”. W nim rozpoczyna się i kończy wykonywanie programu. // #include <iostream> #include <vector> #include <algorithm> const int MAX_N = 500020; const int MAX_LOG_N = 20; long long color_max[1 << 21]; long long temp_col[MAX_N + 1]; int pow2[21] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576 }; //long long color_max[MAX_N]; long long access_outer_max(int x, int s, long long *a) { //if S=1 returns 0 long long cur_max = 0; for (int i = 0; i < s - 1; i++) { cur_max = std::max(cur_max, a[x ^ 1]); x = (x >> 1) | (1 << s ); } return cur_max; } void update_single(int x, long long val, int s, long long *a) { if (a[x] >= val) return; //NO NEED TO UPADTE a[x] = val; for (int i = 0; i < s; i++) { x = (x >> 1) | (1 << s); if (a[x] >= val) return; // NO NEED FOR FURTHER UPDATE a[x] = val; } } void update_all(int s, long long *a) { int x = 0; int prev_x = 0; for (int level = s - 1; level >= 0; level--) { x = (x >> 1) | (1 << s); for (int i = 0; i < (1 << level); i++) { a[x | i] = std::max(a[prev_x | (i << 1) | 1], a[prev_x | (i << 1)]); } prev_x = x; } } long long access_all_max(int s, long long *a) { return a[(1 << (s + 1)) - 2]; } int main() { std::vector<std::pair<int, int>> blocks = std::vector<std::pair<int, int>>(); //(SIZE, COLOR) int n, c; std::cin >> n; std::cin >> c; for (int i = 0; i < (1 << 21); i++) color_max[i] = 0; for (int i = 0; i < MAX_N + 1; i++) temp_col[i] = 0; for (int i = 0; i < n; i++) { int a, w; std::cin >> a >> w; blocks.push_back({ a,w }); } std::sort(begin(blocks), end(blocks), std::less<std::pair<int,int>>()); int cur_size = 0; int pos = 0; while (pos < n) { long long cur_size = blocks[pos].first; int last_pos = pos; while (pos < n && blocks[pos].first == cur_size) { pos++; } pos--; std::vector<int> considered_col = std::vector<int>(); //CALCULATE PROFIT FOR EACH EQUAL SIZED BLOCK for (int i = last_pos; i <= pos; i++) { long long tmp = access_outer_max(blocks[i].second, 20, color_max); long long profit = 0; if (tmp != 0) profit = tmp + blocks[i].first - c; else // THE BEST WAS AS GOOD AS NOT USING ANY BLOCKS ABOVE profit = blocks[i].first; profit = std::max(profit, color_max[blocks[i].second] + blocks[i].first); temp_col[blocks[i].second] = std::max(temp_col[blocks[i].second], profit); considered_col.push_back( blocks[i].second ); } // UPDATE THE STORED PROFITS for (int i = 0; i < considered_col.size(); i++) { if (temp_col[considered_col[i]] != 0LL) { update_single(considered_col[i], temp_col[considered_col[i]], 20, color_max); temp_col[considered_col[i]] = 0; } } std::cout << ""; /*// ŹLE PRZECZYTAŁEM ZADANIE. ROZWIĄZYWAŁEM TRUDNIEJSZY WARIANT WIEŻY, GDZIE DOPUSZAM RÓWNE DŁUGOŚCI KLOCKÓW block_sec.push_back({ count, prev_color }); std::sort(begin(block_sec), end(block_sec), std::greater<>()); int end_upper = 0; for (int i = 0; i < block_sec.size(); i++) { if (block_sec[i].first * cur_size >= c) { end_upper++; } else break; } auto tmp = std::upper_bound(std::begin(pow2), std::end(pow2), block_sec.size()); int block_s = std::distance(std::begin(pow2), tmp); long long upper_profit = 0; //PRECOMPUTATION for (int i = 0; i < end_upper; i++) { //FOR THE PROFITABLE upper_sec_max[i] = std::max(access_outer_max(block_sec[i].second, 19, color_max) - c, color_max[block_sec[i].second]); // PROFIT FROM CHOOSING END OF THIS COLOR (LENGTH OF THE BLOCK NOT COUNTED) upper_profit += block_sec[i].first * cur_size; } upper_profit -= (end_upper - 1)*c; update_all(block_s, upper_sec_max); for (int i = end_upper; i < block_sec.size(); i++) { //FOR THE UNPROFITABLE I ADD THE GAIN FROM IT HEIGHT AND MINUS THE ADITIONAL COST; lower_sec_max[i] = std::max (access_outer_max(block_sec[i].second, 19, color_max) - c, color_max[block_sec[i].second]) + block_sec[i].first*cur_size - c; //PROFIT FROM CHOOSING END OF THIS COLOR (+ LENGTH OF THE BLOCK AND SWITCHING COST) } update_all(block_s, lower_sec_max); //ADDING THE BLOCKS TO THE TOWER for (int i = 0; i < end_upper; i++) { //THINK WHAT IF THERE IS ONLY 1 ELEMENT //FOR THE PROFITABLE START //SECTION END ON A DIFFERENT COLOR FROM PROFITABLE long long cur_max = 0; cur_max = std::max(cur_max, access_outer_max(i, block_s, upper_sec_max) + upper_profit); //SECTION END ON A COLOR FROM UNPROFITABLE if (end_upper != block_sec.size()) cur_max = std::max(cur_max, access_all_max(block_s, lower_sec_max) + upper_profit); //SECTION END IS THE SAME //NO SPLITTING cur_max = std::max(cur_max, upper_sec_max[i] + block_sec[i].first*cur_size); //SEGMENT SPLIT WHAT IF THERE ARE NO OTHER !!!!!!!!!!!!!!!!!!!!!!!!! if (block_sec[i].first > 1 && end_upper > 1) { cur_max = std::max(cur_max, upper_sec_max[i] + upper_profit - c*(end_upper > 1)); } update_single(block_sec[i].second, cur_max, 19, color_max); } for (int i = end_upper; i < block_sec.size(); i++) { //FOR THE UNPROFITABLE START long long cur_max = 0; //SECTION END ON A COLOR FROM PROFITABLE if (end_upper != 0) cur_max = std::max(cur_max, access_all_max(block_s, upper_sec_max) + upper_profit - c); //SECTION END ON A DIFFERENT COLOR FROM UNPROFITABLE cur_max = std::max(cur_max, access_outer_max(i, block_s, lower_sec_max) + block_sec[i].first*cur_size); //SECTION END IS THE SAME // NO SPLITTING cur_max = std::max(cur_max, lower_sec_max[i] + c); //SEGMENT SPLIT if (block_sec[i].first > 1 && end_upper > 1) { //upper section not empty and current segment is splittable cur_max = std::max(cur_max, lower_sec_max[i] + upper_profit - 2*c); } update_single(block_sec[i].second, cur_max, 19, color_max); } for (int i = 0; i < (1 << (block_s + 1)); i++) upper_sec_max[i] = 0; for (int i = 0; i < (1 << (block_s + 1) ); i++) lower_sec_max[i] = 0; */ pos++; } std::cout << access_all_max(20, color_max); } |
English