POJ 2958
解き方に気づけば簡単。ちなみに最初に斜めのラインで部分和を計算しておけば、とか思ったけどナイーブな方法と変わらないぐらい遅かった。
#include <iostream> #include <algorithm> #include <numeric> using namespace std; static const int N = 100; static int optimal(int *d, int n, int total) { int upside = 0; int downside = total; int m = 0; int cur = 0; for (int i = 0; i < n - 1; i++) { upside += d[i]; downside -= d[i]; cur += upside - (total - upside); m = cur < m ? cur : m; } return m; } int main() { int t; cin >> t; while (t--) { int rows, columns; int base_cost = 0; // cost from (0, 0) int total = 0; // sum of count for all blocks int sum_v[N]; // sum of count for each vertical area int sum_h[N]; // sum of count for each horizontal area cin >> columns >> rows; fill(sum_h, sum_h + rows, 0); fill(sum_v, sum_v + columns, 0); for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { int x; cin >> x; sum_h[i] += x; sum_v[j] += x; base_cost += (i + j) * x; } total += sum_h[i]; } int result = base_cost + optimal(sum_h, rows, total) + optimal(sum_v, columns, total); cout << result << " blocks" << endl; } return 0; }
で、適当に縮める。
続きを読む