题解:P6469 [COCI2008-2009#6] NERED
[COCI2008-2009#6] NERED
思路
看到 \(n\le100\) 就知道可以随便折腾。
由题意得,所有格子的权值和为 \(m\),那么变换后的矩形的面积也就是 \(m\)。
对于一个面积为 \(m\) 的矩形,将其变为合法矩形所需要的代价为范围内权值为 \(0\) 的点的个数,直接枚举所有面积为 \(m\) 的矩形即可。
优化
考虑到要多次求不定区间内权值为 \(0\) 的点的个数,可以使用前缀和优化,这里不再过多赘述。
未优化的时间复杂度约为 \(O\left(n^2 \times m^{3/2}\right)\),优化后约为 \(O\left(n^2 \times \sqrt{m}\right)\)。
因为数据太小,优化的效果不大:

未优化代码:
#include<bits/stdc++.h>
using namespace std;
int n, m, x, y, k[105][105], sum[105][105], ans=0x3f3f3f;
int main() {
cin >> n >> m;
for(int i=1; i<=m; i++) {
cin >> x >> y;
k[x][y]++;
}
for(int len1=1, len2; len1<=m; len1++) { //枚举长宽
if(m%len1) continue;
len2=m/len1;
//枚举起始点
for(int x1=1; x1+len1-1<=n; x1++) {
for(int y1=1; y1+len2-1<=n; y1++) {
int t=0;
//统计权值为0的点的个数
for(int x=x1; x<=x1+len1-1; x++) {
for(int y=y1; y<=y1+len2-1; y++) {
if(!k[x][y]) t++;
}
}
ans=min(ans, t);
}
}
}
cout << ans;
}
优化代码:
#include<bits/stdc++.h>
using namespace std;
int n, m, x, y, k[105][105], sum[105][105], ans=0x3f3f3f;
int main() {
cin >> n >> m;
for(int i=1; i<=m; i++) {
cin >> x >> y;
k[x][y]++;
}
//求前缀和
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(!k[i][j]);
}
}
for(int len1=1, len2; len1<=m; len1++) { //枚举长宽
if(m%len1) continue;
len2=m/len1;
//枚举起始点
for(int x1=1, x2; (x2=x1+len1-1)<=n; x1++) {
for(int y1=1, y2; (y2=y1+len2-1)<=n; y1++) {
ans=min(ans, sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]); //更新答案
}
}
}
cout << ans;
}

浙公网安备 33010602011771号