[AtCoder] ABC 189 C – Mandarin Orange
問題
方針
\( x = A_i \) としたとき、\( i – 1\) 番目から先頭に向かって、\( A_i \leq A_j \) を連続的に満たす \( j \) の個数を \( a \) とします。また、\( i + 1 \) 番目から末尾に向かって、\( A_j \leq A_j \) を連続的に満たす \( j \) の個数を \( b \) とします。このとき、みかんを食べる個数は、\( (a + b + 1)x \) となります。
したがって、全ての \(A_i \) について、\( a, b \) を求めれば良いので、平方分割を使って求めます。平方分割を行うに当たり、数列 \( A \) の大きさを \( 10^4 \) と固定し、\( N \) 以降の \( A_i \) の値は \( 0 \) とします。バケットとなる数列を \( B \) とし、サイズは \( 100 \) とします。このとき、\( B_i \) の値は、\( 100i \leq j < 100(i + 1) \) を満たす \( A_j \) の最小値とします。この値を利用することで、\( a, b \) を高速に求められます。
コード
#include <bits/stdc++.h> using namespace std; typedef long long ll; int N; const int M = 10000; const int m = 100; int A[M], B[m]; void init() { int min_v = 1000000; for (int i = 0; i < m; i++) { min_v = 1000000; for (int j = i * m; j < (i + 1) * m; j++) { min_v = min(min_v, A[j]); } B[i] = min_v; } } int getLeft(int i) { int ret = 0; int b = i / m; // iが所属するバケットの要素番号 // iが所属するバケット内を走査 for (int j = i - 1; j >= b * m; j--) { if (A[j] >= A[i]) ret++; else return ret; } if (b == 0) return ret; b--; while (b >= 0) { if (B[b] >= A[i]) b--; else break; } if (b == -1) return ret + m * (i / m); for (int j = (b + 1) * m - 1; j >= b * m; j--) { if (A[j] >= A[i]) ret++; else break; } return ret + m * (i / m - b - 1); } int getRight(int i) { int b = i / m; int ret = 0; for (int j = i + 1; j < (b + 1) * m; j++) { if (A[j] >= A[i]) ret++; else return ret; } if (b == m - 1) return ret; b++; while (b < m) { if (B[b] >= A[i]) b++; else break; } if (b == m) return ret + m * (m - i / m - 1); for (int j = b * m; j < (b + 1) * m; j++) { if (A[j] >= A[i]) ret++; else break; } return ret + m * (b - i / m - 1); } int main() { cin >> N; int best = 0; fill(A, A + M, 0); fill(B, B + m, 0); for (int i = 0; i < N; i++) { cin >> A[i]; } init(); for (int i = 0; i < N; i++) { int l = 1 + getLeft(i) + getRight(i); best = max(best, A[i] * l); } cout << best << "\n"; return 0; }
ディスカッション
コメント一覧
まだ、コメントがありません