E. Omkar and Last Floor
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Omkar is building a house. He wants to decide how to make the floor plan for the last floor.
Omkar's floor starts out as n rows of m zeros (1≤n,m≤100). Every row is divided into intervals such that every 0 in the row is in exactly 1 interval. For every interval for every row, Omkar can change exactly one of the 0s contained in that interval to a 1. Omkar defines the quality of a floor as the sum of the squares of the sums of the values in each column, i. e. if the sum of the values in the i-th column is qi, then the quality of the floor is ∑mi=1q2i.
Help Omkar find the maximum quality that the floor can have.
Input
The first line contains two integers, n and m (1≤n,m≤100), which are the number of rows and number of columns, respectively.
You will then receive a description of the intervals in each row. For every row i from 1 to n: The first row contains a single integer ki (1≤ki≤m), which is the number of intervals on row i. The j-th of the next ki lines contains two integers li,j and ri,j, which are the left and right bound (both inclusive), respectively, of the j-th interval of the i-th row. It is guaranteed that all intervals other than the first interval will be directly after the interval before it. Formally, li,1=1, li,j≤ri,j for all 1≤j≤ki, ri,j−1+1=li,j for all 2≤j≤ki, and ri,ki=m.
Output
Output one integer, which is the maximum possible quality of an eligible floor plan.
Example
inputCopy
4 5
2
1 2
3 5
2
1 3
4 5
3
1 1
2 4
5 5
3
1 1
2 2
3 5
outputCopy
36
题意:n * m的全 0 矩阵,每一行被分成几个区间,对于每个区间,你可以把这个区间中的某个数变成 1 ,设操作完后 num[j] 表示第 j 列 1 的个数, 求 ({sum_{j = 1}^m {num[j]^2}})。
思路:区间dp, dp[i][j] 表示, 第 i 列到第 j 列的最大解, 容易得出转移方程, dp[i][j] = max(dp[i][j], dp[i][k - 1] + cnt[k] * cnt[k] + dp[k + 1][j])。(cnt[k]的意义请看代码)
但是,可能会有一个问题,按前面的 dp[i][j] 的定义的话不能保证不会出现矛盾,所以 dp[i][j] 表示每行中那些区间范围包含于[i, j] 的区间对 dp[i][j] 的最大贡献值。
这样就不会矛盾了。
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <set>
#include <math.h>
using namespace std;
typedef long long LL;
const int maxn = 105;
int INF = 1e9;
int n, m;
int L[maxn][maxn], R[maxn][maxn], dp[maxn][maxn];
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++){
int num;
scanf("%d", &num);
while(num--){
int le, ri;
scanf("%d%d", &le, &ri);
for(int j = le; j <= ri; j++){
L[i][j] = le, R[i][j] = ri;
}
}
}
for(int len = 1; len <= m; len++){
for(int i = 1; i + len - 1 <= m; i++){
int j = len + i - 1;
for(int mid = i; mid <= j; mid++){
int cnt = 0;
for(int k = 1; k <= n; k++){
if(L[k][mid] >= i && R[k][mid] <= j) cnt++; // 只考虑所处的区间范围在[i, j] 之间的点
}
dp[i][j] = max(dp[i][j], dp[i][mid - 1] + cnt * cnt + dp[mid + 1][j]);
}
}
}
printf("%d
", dp[1][m]);
return 0;
}