제출 #530913

#제출 시각아이디문제언어결과실행 시간메모리
530913danielliu04Nafta (COI15_nafta)C++17
100 / 100
525 ms144480 KiB
// Link: https://oj.uz/problem/view/COI15_nafta

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define ld long double
// #define lc (node<<1)+1
// #define rc (node<<1)+2
#define endl '\n'
// #define INF 1e18


const int max_n = 2002;

int n, m;

int matrix[max_n][max_n];
int I[max_n][max_n];
int W[max_n][max_n];
bool visited[max_n][max_n];
int opt[max_n][max_n]; // this is the optimal index for each dp

int dp[max_n][max_n];

int curr_sum, left_most, right_most;

int vr[4] = {0, 0, -1, 1};
int vc[4] = {1, -1, 0, 0};

bool valid(int i, int j){
	return i >= 0 && j >= 0 && i < n && j < m && !visited[i][j] && matrix[i][j] != -1;
}
void dfs(int i, int j){
	visited[i][j] = 1;
	curr_sum += matrix[i][j];
	left_most = min(left_most, j);
	right_most = max(right_most, j);

	for(int x = 0; x < 4; x ++){
		int ni = i + vr[x], nj = j + vc[x];
		if(valid(ni, nj)) dfs(ni, nj);
	}
}

int get_w(int i, int j){
	if(i == -1) return W[i+1][j] + I[i+1][j];
	else return W[i][j];
}

int get_dp(int i, int j){
	if(i == -1) return 0;
	else return dp[i][j];
}

void compute(int j, int left = 0, int right = m-1, int optl = -1, int optr = m-1){

	if(left > right) return;

	int mid = (left + right) / 2;
	// find the best answer for mid

	int opt_i = -2, res = 0;

	for(int k = optl; k <= min(mid-1, optr); k ++){
		if(opt_i == -2 || get_w(k, mid) + get_dp(k, j-1) > res){
			opt_i = k;
			res = get_w(k, mid) + get_dp(k, j-1);
		}
	}

	dp[mid][j] = res;
	opt[mid][j] = opt_i;

	compute(j, left, mid-1, optl, opt_i);
	compute(j, mid + 1, right, opt_i, optr);
}

int main() {

	// ios_base::sync_with_stdio(0);
	// cin.tie(0);	

	cin >> n >> m;

	for(int i = 0; i < n; i ++){
		string row; cin >> row;
		for(int j = 0; j < m; j ++){
			if(row[j] == '.') matrix[i][j] = -1;
			else matrix[i][j] = row[j] - '0';
		}
	}

	// cout << "here" << endl;


	// find all connected components and compute I
	for(int i = 0; i < n; i ++){
		for(int j = 0; j < m; j ++){
			if(matrix[i][j] != -1 && !visited[i][j]){
				curr_sum = 0; left_most = right_most = j;
				dfs(i, j);
				I[left_most][left_most] += curr_sum;
				I[left_most][right_most + 1] -= curr_sum;
			}
		}
	}

	// cout << "here" << endl;

	for(int i = 0; i < m; i ++){
		for(int j = 1; j < m; j ++){
			I[i][j] += I[i][j-1];
		}
	}

	// then compute W
	for(int j = 0; j < m; j ++){
		W[j][j] = 0; // no way
		for(int i = j-1; i >= 0; i --){
			W[i][j] = W[i+1][j] + I[i+1][j];
		}
	}

	// cout << "here" << endl;

	// Now do the most simple dp transition
	// dp[i][j] -> maximum oil using the i-th col as the last with j pumps

	for(int i = 0; i <= m; i ++){
		for(int j = 0; j <= m; j ++){
			opt[i][j] = -1;
		}
	}

	// for(int j = 1; j <= m; j ++){
	// 	for(int i = j - 1; i < m; i ++){
	// 		for(int k = i - 1; k >= j-2; k --){
	// 			if(opt[i][j] == -1 || get_w(k, i) + get_dp(k, j - 1) >= dp[i][j]){
	// 				opt[i][j] = k;
	// 				dp[i][j] = get_w(k, i) + get_dp(k, j - 1);
	// 			}
	// 		}
	// 	}
	// }

	for(int j = 1; j <= m; j ++){
		compute(j);
	}

	for(int j = 1; j <= m; j ++){
		int res = 0;
		for(int i = 0; i < m; i ++){
			res = max(res, dp[i][j]);
		}
		cout << res << endl;
	}
}	
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...