題意
給定一個數組,求 Aj + Ai - (j - i) 的最大值,其中 j > i,數組長度範圍是 50000。
題解
Aj + Ai - (j - i) = (Aj - j) + (Ai + i)
所以我們可以把原來的數組 a 轉化成兩個數組 aj, ai,其中 ajj = Aj - j, aii = Ai + i,那麼 max{aii + ajj} (i<j) 即爲所求。
假設 ajj 固定,如果能夠知道 max{aii} (i<j) 的話,那麼對於前 j 個數字,最大值就得到了。於是我們可以提前求出前 i 個數字的 max{ai},記爲數組 pai,複雜度是 O(n)。然後循環 aj 數組,得到 ajj + paij-1 的最大值即爲題目所求,這一步複雜度還是 O(n)。整個複雜度是 O(n)。
1 class Solution { 2 public: 3 int maxScoreSightseeingPair(vector<int>& A) { 4 VI ai(A.size()), aj(A.size()), pai(A.size()); 5 int res=-1; 6 REP(i, A.size()) { 7 ai[i]=A[i]+i; 8 aj[i]=A[i]-i; 9 if(i==0) { 10 pai[i]=ai[i]; 11 } else { 12 pai[i]=max_(pai[i-1],ai[i]); 13 res=max_(res,pai[i-1]+aj[i]); 14 } 15 } 16 return res; 17 } 18 };
在這個基礎上優化代碼:
1 class Solution { 2 public: 3 int maxScoreSightseeingPair(vector<int>& A) { 4 // A.size() >= 2 5 VI pai(A.size()); 6 int res=A[1]+A[0]-1; 7 pai[0]=A[0]; 8 REP_1(i, A.size()-1) { 9 pai[i]=max_(pai[i-1],A[i]+i); 10 res=max_(res,pai[i-1]+A[i]-i); 11 } 12 return res; 13 } 14 };
觀察數組的使用方式,發現後一個元素只依賴於前一個元素,所以還可以再優化:
1 class Solution { 2 public: 3 int maxScoreSightseeingPair(vector<int>& A) { 4 // A.size() >= 2 5 int res=A[1]+A[0]-1, tmp=A[0]; 6 REP_1(i, A.size()-1) { 7 res=max_(res,tmp+A[i]-i); 8 tmp=max_(tmp,A[i]+i); 9 } 10 return res; 11 } 12 };
這樣可讀性其實變差了,但是節省了空間。
最後貼上完整的代碼:
1 // ================================================== 2 3 // C library 4 #include <cassert> 5 #include <cmath> 6 #include <climits> 7 #include <cstdio> 8 #include <cstdlib> 9 #include <cstring> 10 #include <cctype> 11 #include <ctime> 12 13 // Containers 14 #include <vector> 15 #include <list> 16 #include <stack> 17 #include <queue> 18 #include <deque> 19 #include <set> 20 #include <map> 21 #include <unordered_set> 22 #include <unordered_map> 23 24 // Input/Output 25 #include <iostream> 26 #include <istream> 27 #include <ostream> 28 #include <sstream> 29 #include <fstream> 30 #include <ios> 31 #include <iomanip> 32 33 // Other 34 #include <tuple> 35 #include <string> 36 #include <tuple> 37 #include <bitset> 38 #include <algorithm> 39 #include <utility> 40 #include <type_traits> 41 #include <iterator> 42 #include <limits> 43 #include <stdexcept> 44 #include <random> 45 #include <chrono> 46 47 // ================================================== 48 49 using namespace std; 50 51 // constants 52 const double EPS = 1e-9; 53 54 // type alias 55 using PII = pair<int, int>; 56 using LL = long long int; 57 using VI = vector<int>; 58 using VC = vector<char>; 59 using VS = vector<string>; 60 using VVI = vector<VI>; 61 using MII = map<int, int>; 62 using MCI = map<char, int>; 63 using SI = set<int>; 64 65 // ================================================== 66 67 // fast IO 68 static auto __2333__ = []() { 69 ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }(); 70 71 // ================================================== 72 73 // some macro for less typing 74 #define max_(x, y) ((x) > (y) ? (x) : (y)) 75 #define min_(x, y) ((x) > (y) ? (y) : (x)) 76 77 #define REP(i, n) for (int i = 0; i < int(n); ++i) // [0, n) 78 #define REPV(i, n) for (int i = int(n - 1); i >= 0; --i) // reverse [0, n) 79 #define FOR(i, a, b) for (int i = int(a); i < int(b); ++i) // [a, b) 80 #define DWN(i, b, a) for (int i = int(b - 1); i >= int(a); --i) // reverse [a, b) 81 82 #define REP_1(i, n) for (int i = 1; i <= int(n); ++i) // [1, n] 83 #define REPV_1(i, n) for (int i = int(n); i >= 1; --i) // reverse [1, n] 84 #define FOR_1(i, a, b) for (int i = int(a); i <= int(b); ++i) // [a, b] 85 #define DWN_1(i, b, a) for (int i = int(b); i >= a; --i) // reverse [a, b] 86 87 // DEBUG PRINT macro 88 #define PR(x) cout << #x " = " << (x) << " " 89 #define NL cout << " " 90 91 #define PR1(x) PR(x), NL 92 #define PR2(x1, x2) PR(x1), PR1(x2) 93 #define PR3(x1, x2, x3) PR(x1), PR2(x2, x3) 94 #define PR4(x1, x2, x3, x4) PR(x1), PR3(x2, x3, x4) 95 96 int direction[8][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1}, 97 {-1, -1}, {-1, 1}, {1, -1}, {1, 1} }; 98 99 // ================================================== 100 101 // simplest print 102 template<typename T> 103 void PRC(const T& a) { cout << a << " "; } 104 105 // print container 106 template<typename T> 107 void PRCO(const T& c) { for (auto x : c) PRC(x); NL; } 108 109 // print vector 110 template<typename T> 111 void PRV(const vector<T>& c) { PRCO<vector<T>>(c); } 112 113 // print C-style array 114 template<typename T, size_t N> 115 void PRA(const T (&ar)[N]) { 116 for (auto x : ar) PRC(x); NL; 117 } 118 119 // print pair 120 template<typename T1, typename T2> 121 void PRP(const pair<T1, T2>& p) { PRC(p.first); PRLN(p.second); } 122 123 // print a value and a new line 124 template<typename T> 125 void PRLN(const T& a) { cout << a << " "; } 126 127 // ================================================== 128 // math 129 bool is_prime(LL x) 130 { 131 if (x == 1) return false; 132 assert(x > 1); 133 LL m = ceil(sqrt(x)); 134 FOR_1(i, 2, m) { if (!(x % i)) return false; } 135 return true; 136 } 137 138 // prime table 139 const int PRIME_MAX = 10; 140 VI prime_table; 141 vector<bool> prime_table_bool(PRIME_MAX, true); 142 143 void get_prime() { 144 FOR_1(i, 2, PRIME_MAX) { 145 if (prime_table_bool[i]) { 146 prime_table.push_back(i); 147 for (int j = i << 1; j <= PRIME_MAX; j += i) prime_table_bool[j] = false; 148 } 149 } 150 } 151 152 // double equals 153 bool eq(double a, double b) { return fabs(a - b) < EPS; } 154 155 double random_() { 156 // generate random number in [0, 1] 157 return double(rand()) / RAND_MAX; 158 } 159 160 int random_(int m) { 161 // generate random int between [0, m - 1] 162 return int(random_() * (m - 1) + 0.5); 163 } 164 165 // high precision integer 166 167 class BNI { 168 friend ostream &operator<<(ostream &, const BNI &); 169 friend istream &operator>>(istream &, BNI &); 170 public: 171 BNI() = default; 172 BNI(const string &s) { *this = s; } 173 BNI(const char s[]) :BNI(string(s)) {} 174 BNI(const BNI &rhs) = default; 175 BNI(const LL n) { *this = n; }; 176 BNI(istream &in) { string s; in >> s; *this = s; } 177 178 BNI &operator=(const BNI &rhs) = default; 179 BNI &operator=(const string &s) { 180 string s_ = clean_zero_str(s); 181 num.resize(s_.size()); 182 int i = 0; 183 for (auto it = s_.crbegin(); it != s_.crend(); ++it) 184 num[i++] = *it - '0'; 185 return *this; 186 } 187 BNI &operator=(const char s[]) { 188 operator=(string(s)); 189 return *this; 190 } 191 BNI &operator=(LL n) { 192 stringstream ss; ss << n; 193 string s; ss >> s; 194 *this = s; 195 return *this; 196 } 197 BNI operator+(const BNI &rhs) const { 198 BNI res; 199 size_t max_len = max_(num.size(), rhs.num.size()); 200 int x; 201 for (int i = 0, rem = 0; rem || i < max_len; ++i) { 202 x = rem; 203 if (i < num.size()) x += num[i]; 204 if (i < rhs.num.size()) x += rhs.num[i]; 205 res.num.push_back(x % 10); 206 rem = x / 10; 207 } 208 res.clean_zero(); 209 return res; 210 } 211 BNI& operator+=(const BNI &rhs) { 212 *this = *this + rhs; 213 return *this; 214 } 215 BNI operator*(const BNI &rhs) const { 216 BNI res; 217 size_t sum_len = num.size() + rhs.num.size(); 218 res.num.resize(sum_len); 219 for (size_t i = 0; i < num.size(); ++i) { 220 for (size_t j = 0; j < rhs.num.size(); ++j) { 221 res.num[i + j] += num[i] * rhs.num[j]; 222 } 223 } 224 for (size_t i = 0; i < res.num.size() - 1; ++i) { 225 res.num[i + 1] += res.num[i] / 10; 226 res.num[i] %= 10; 227 } 228 res.clean_zero(); 229 return res; 230 } 231 BNI& operator*=(const BNI &rhs) { 232 *this = *this * rhs; 233 return *this; 234 } 235 /* 236 * assume *this >= rhs 237 */ 238 BNI operator-(const BNI &rhs) const { 239 assert(*this >= rhs); 240 if (rhs == 0LL) return *this; 241 BNI res; 242 int x; 243 for (int i = 0, rem = 0; i < num.size(); ++i) { 244 x = num[i] - rem; 245 if (i < rhs.num.size()) x -= rhs.num[i]; 246 if (x >= 0) rem = 0; 247 else { rem = 1; x += 10; } 248 res.num.push_back(x); 249 } 250 res.clean_zero(); 251 return res; 252 } 253 BNI& operator-=(const BNI &rhs) { 254 *this = *this - rhs; 255 return *this; 256 } 257 /* 258 * assume rhs is not zero 259 */ 260 pair<BNI, BNI> operator/(const BNI &rhs) const { 261 assert(BNI(0LL) != rhs); 262 if (*this < rhs) return make_pair(0LL, *this); 263 264 BNI quotient, rem; 265 string nume = c_str(); 266 string numerator = nume.substr(0, rhs.num.size()); 267 size_t pos = rhs.num.size(); 268 vector<BNI> times(10); 269 for (int i = 0; i < 10; ++i) times[i] = rhs * i; 270 string quot; 271 272 while (pos <= nume.size()) { 273 BNI nume_b = numerator; 274 int cnt = 0; 275 276 while (cnt < 10 && times[cnt] <= nume_b) ++cnt; 277 --cnt; 278 279 quot += char(cnt + '0'); 280 rem = nume_b - times[cnt]; 281 282 if (pos < nume.size()) 283 numerator = rem.c_str() + nume[pos]; 284 285 ++pos; 286 } 287 288 quotient = quot; 289 290 return make_pair(quotient, rem); 291 } 292 bool operator<(const BNI &rhs) const { 293 if (num.size() == 0) return !(rhs.num.size() == 0); 294 if (num.size() != rhs.num.size()) { 295 return num.size() < rhs.num.size(); 296 } 297 for (int i = num.size() - 1; i >= 0; --i) { 298 if (num[i] != rhs.num[i]) return num[i] < rhs.num[i]; 299 } 300 return false; 301 } 302 bool operator>(const BNI &rhs) const { return rhs < *this; } 303 bool operator<=(const BNI &rhs) const { return !(*this > rhs); } 304 bool operator>=(const BNI &rhs) const { return !(*this < rhs); } 305 bool operator!=(const BNI &rhs) const { return (*this < rhs) || (*this > rhs); } 306 bool operator==(const BNI &rhs) const { return !(*this != rhs); } 307 size_t size() const { return num.size(); } 308 string c_str() const { 309 string s; 310 for (auto x : num) s = char(x + '0') + s; 311 return s.empty() ? "0" : s; 312 } 313 void left_shift() { 314 if (!num.empty()) num.pop_back(); 315 } 316 protected: 317 vector<int> num; 318 string clean_zero_str(const string &s) { 319 if (s.empty() || s[0] != '0') return s; 320 size_t i = 0; 321 while (i < s.size() && '0' == s[i]) ++i; 322 return s.substr(i); 323 } 324 void clean_zero() { 325 for (auto it = num.rbegin(); it != num.rend() && *it == 0;) { 326 ++it; 327 num.pop_back(); 328 } 329 } 330 }; 331 332 ostream &operator<<(ostream &out, const BNI &x) { 333 out << x.c_str(); 334 return out; 335 } 336 337 istream &operator>>(istream &in, BNI &x) { 338 x = BNI(in); 339 return in; 340 } 341 342 // high precision float 343 class BNF : protected BNI { 344 friend ostream &operator<<(ostream &out, const BNF &x); 345 friend istream &operator>>(istream &in, BNF &x); 346 public: 347 BNF() = default; 348 BNF(const string &s) { *this = s; } 349 BNF(const char s[]): BNF(string(s)) {} 350 BNF(const BNF &rhs) = default; 351 BNF(const LL n) { *this = n; } 352 BNF(istream &in) { string s; in >> s; *this = s; } 353 354 BNF &operator=(const string &s) { 355 string s_ = clean_zero_str(s); 356 num.resize(s_.size()); 357 int i = 0; 358 for (auto it = s_.crbegin(); it != s_.crend(); ++it) 359 num[i++] = *it - '0'; 360 return *this; 361 } 362 BNF &operator=(const char s[]) { 363 operator=(string(s)); return *this; 364 } 365 BNF &operator=(LL n) { 366 stringstream ss; ss << n; 367 string s; ss >> s; 368 *this = s; 369 return *this; 370 } 371 BNF operator+(const BNF &rhs) const { 372 pair<string, string> in_fr1 = split(), in_fr2 = rhs.split(); 373 string inte1 = in_fr1.first, frac1 = in_fr1.second, 374 inte2 = in_fr2.first, frac2 = in_fr2.second; 375 LL inc = 0LL; 376 BNI frac_sum; 377 inc += sum_has_carry(frac1, frac2, frac_sum); 378 BNI inte_sum = BNI(inte1) + inte2 + inc; 379 380 return join_inte_frac(inte_sum, frac_sum); 381 } 382 BNF& operator+=(const BNF &rhs) { 383 *this = *this + rhs; 384 return *this; 385 } 386 /* 387 * assume *this >= rhs 388 */ 389 BNF operator-(const BNF &rhs) const { 390 assert(*this >= rhs); 391 pair<string, string> in_fr1 = split(), in_fr2 = rhs.split(); 392 string inte1 = in_fr1.first, frac1 = in_fr1.second, 393 inte2 = in_fr2.first, frac2 = in_fr2.second; 394 LL dec = 0LL; 395 if (BNI(frac1) < frac2) { 396 frac1 = '1' + frac1; ++dec; 397 } 398 while (frac1.size() < frac2.size()) frac1 += '0'; 399 while (frac2.size() < frac1.size()) frac2 += '0'; 400 BNI frac = BNI(frac1) - frac2; 401 BNI inte = BNI(inte1) - dec - inte2; 402 return join_inte_frac(inte, frac); 403 } 404 BNF& operator-=(const BNF &rhs) { 405 return *this = *this - rhs; 406 } 407 BNF operator*(const BNF &rhs) const { 408 pair<string, string> in_fr1 = split(), in_fr2 = rhs.split(); 409 string inte1 = in_fr1.first, frac1 = in_fr1.second, 410 inte2 = in_fr2.first, frac2 = in_fr2.second; 411 BNI res = BNI(inte1 + frac1) * (inte2 + frac2); 412 int deci = decimals + rhs.decimals; 413 string res_s = res.c_str(); 414 while (res_s.size() < deci) res_s = '0' + res_s; 415 return BNF(res_s.substr(0, res_s.size() - deci) + '.' 416 + res_s.substr(res_s.size() - deci)); 417 } 418 BNF& operator*=(const BNF &rhs) { 419 return *this = *this * rhs; 420 } 421 bool operator<(const BNF &rhs) const { 422 pair<string, string> in_fr1 = split(), in_fr2 = rhs.split(); 423 string inte1 = in_fr1.first, frac1 = in_fr1.second, 424 inte2 = in_fr2.first, frac2 = in_fr2.second; 425 if (inte1 < inte2) return true; 426 else if (inte1 == inte2) return frac1 < frac2; 427 else return false; 428 } 429 bool operator>(const BNF &rhs) const { return rhs < *this; } 430 bool operator<=(const BNF &rhs) const { return !(*this > rhs); } 431 bool operator>=(const BNF &rhs) const { return !(*this < rhs); } 432 bool operator!=(const BNF &rhs) const { return (*this < rhs) || (*this > rhs); } 433 bool operator==(const BNF &rhs) const { return !(*this != rhs); } 434 435 protected: 436 int decimals = 0; 437 LL sum_has_carry(const BNI &a, const BNI &b, BNI &sum) const { 438 int max_len = max_(a.size(), b.size()); 439 sum = a + b; 440 if (sum.size() > max_len) { sum.left_shift(); return 1LL; } 441 return 0LL; 442 } 443 BNF join_inte_frac(const BNI &inte, const BNI &frac) const { 444 return BNF(inte.c_str() + "." + frac.c_str()); 445 } 446 string clean_tail_zero_str(const string &s) { 447 int i = 0; 448 string r; 449 while (i < s.size() && '.' != s[i]) r += s[i++]; 450 451 int j = s.size() - 1; 452 while (j >= 0 && '0' == s[j]) --j; 453 for (int k = i + 1; k <= j; ++k) r += s[k]; 454 decimals = j >= i ? j - i : 0; 455 return r; 456 } 457 string clean_zero_str(const string &s) { 458 string r = BNI::clean_zero_str(s); 459 return clean_tail_zero_str(r); 460 } 461 string c_str() const { 462 string s; 463 for (int i = 0; i < num.size(); ++i) { 464 if (i == decimals) s = '.' + s; 465 s = char(num[i] + '0') + s; 466 } 467 if (s.empty()) s = "0"; 468 if (num.size() == decimals) s = '.' + s; 469 return s; 470 } 471 pair<string, string> split() const { 472 string s = c_str(); 473 size_t p = s.find('.'); 474 return make_pair(s.substr(0, p), s.substr(p + 1)); 475 } 476 }; 477 478 ostream &operator<<(ostream &out, const BNF &x) { 479 cout << x.c_str(); return out; 480 } 481 482 istream &operator>>(istream &in, BNF &x) { 483 x = BNF(in); return in; 484 } 485 486 // Trie Tree 487 const int ALPHASIZE = 26; 488 489 class TrieNode { 490 public: 491 TrieNode() 492 :wordEnd{false}, cnt{1} 493 { 494 REP(i, ALPHASIZE) { child[i] = nullptr; } 495 } 496 ~TrieNode() {} 497 void insert(string word) { 498 int i; 499 TrieNode *cur = this; 500 for (auto x:word) { 501 i = x - 'a'; 502 if (nullptr == cur->child[i]) { 503 cur->child[i] = new TrieNode(); 504 cur = cur->child[i]; 505 } else { 506 cur = cur->child[i]; 507 ++cur->cnt; 508 } 509 } 510 cur->wordEnd = true; 511 } 512 bool search(string word) { 513 int i; 514 TrieNode *cur = this; 515 for (auto x:word) { 516 i = x - 'a'; 517 if (nullptr == cur->child[i]) { 518 return false; 519 } 520 cur = cur->child[i]; 521 } 522 return cur->wordEnd; 523 } 524 int cnt_words(string word) { 525 int i; TrieNode *cur = this; 526 for(auto x:word) { 527 i = x - 'a'; 528 if (nullptr == cur->child[i]) return 0; 529 cur = cur->child[i]; 530 } 531 return cur->cnt; 532 } 533 TrieNode *child[ALPHASIZE]; 534 bool wordEnd; 535 int cnt; // number of words with the prefix 536 }; 537 538 539 540 // ================================================== 541 542 543 // accepted version 3 544 545 class Solution { 546 public: 547 int maxScoreSightseeingPair(vector<int>& A) { 548 // A.size() >= 2 549 int res=A[1]+A[0]-1, tmp=A[0]; 550 REP_1(i, A.size()-1) { 551 res=max_(res,tmp+A[i]-i); 552 tmp=max_(tmp,A[i]+i); 553 } 554 return res; 555 } 556 }; 557 558 int main( void ) { 559 560 #ifdef DEBUG 561 freopen("c.in", "r", stdin); 562 #endif 563 564 Solution sol; 565 int x; VI a; 566 while (cin>>x) { 567 a.push_back(x); 568 } 569 PRCO(a); 570 PRLN(sol.maxScoreSightseeingPair(a)); 571 572 return 0; 573 }
end.