题意:图片分成一格一格的像素点,输入一张图的各个像素值,输出转化后图片的像素值。首先输入图片的宽度,即一行的像素点个数。图片像素的描述方式是run length ecoding(RLE),即一组数(V,L)表示连续L个点的像素值为V。将每个像素点的值与周围的像素点值分别求差,取绝对值的最大值,这个值就是输出图片中的对应点。
分析:因为像素点个数最多有10^9个,所以不可能将所有像素点存在数组中,会MLE;也不可能每个点依次计算,会TLE。所以就找一下规律。
A A A B B
C C C C D
D D D D D
在一般情况下,连续的相同数值在转化后也是一样的,所以只要算一下每一个连续数值段的第一个点转化后的数值,而此时,这一段的第一个必会影响它周围的8个点,所以要同时更新这9个点的数值。
然后讨论特殊情况。
(1)A A A B B
B B B B B
C C C C C
这种情况下,第二行的B与上一行的B转化后的数值不一定是相同的。所以,当某一行存在连续数值段的第一个点时,下一行的第一个点需要特殊讨论。
(2)A A A B B
B B B B B
B B C C C
这种情况下,图片最左下角的那个B与上一行的B转化后的数值不同。所以,还有单独计算一下图片左下角的点。
综上,图片中需要计算的点从10^9个大大缩小,只需要计算每个连续数值段的第一个点及其周围的8个点(最多1000*9个)、连续数值段所在行的下一行的第一个点(最多1000个)、图片左下角的点(1个)。存储时也不需要存全部像素点,只需要存储输入的一组组数(最多1000组)。
唉~以为是水题,没想到花了我一下午的时间。。。还wa了好几发。。多亏了 Discuss里的测试数据呀!
附上链接吧~
Input:http://poj.org/showmessage?message_id=129813
Output:http://poj.org/showmessage?message_id=129814
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int width, v, l, cnt;
int in[1005][2], num[1005];
class Pix{
public:
int val;//像素值
int pos;//序号
bool operator <(Pix y){
return pos < y.pos;
};
}out[10020];
int getcode(int pos, int l, int r){ //得到第pos个点的像素值
if (l == r) //二分查找
return in[l][0];
int mid = (l + r) / 2;
if (pos <= num[mid])
return getcode(pos, l, mid);
else if (pos>num[mid])
return getcode(pos, mid + 1, r);
}
int getvalue(int pos){ //求第pos个点转化后的像素值
int row = (pos - 1) / width;
int col = (pos - 1) % width;
int value = 0;
int code = getcode(pos, 1, cnt - 1);
for (int i = row - 1; i <= row + 1; i++){
for (int j = col - 1; j <= col + 1; j++){
int tp = i*width + j + 1;
if (i < 0 || j < 0 || j >= width || tp > num[cnt - 1])
continue;
int tv = getcode(tp, 1, cnt - 1);
if (value < abs(tv - code))
value = abs(tv - code);
}
}
return value;
}
int main(){
while(cin >> width){
memset(num, 0, sizeof(num));
if (width == 0)
break;
cnt = 1;
while (cin >> v >> l){ //输入
if (v == 0 && l == 0)
break;
in[cnt][0] = v;
in[cnt][1] = l;
num[cnt] = num[cnt - 1] + l;
cnt++;
}
int pos = 1, tmp=0;
for (int k = 1; k < cnt; k++){ //按连续数值段
int row = (pos - 1) / width;
int col = (pos - 1) % width;
for (int i = row - 1; i <= row + 1; i++){ //计算每一段第一个点及其周围8个点转化后的值
for (int j = col - 1; j <= col + 1; j++){
int tp = i*width + j + 1;
if (i < 0 || j<0 || j >= width || tp > num[cnt - 1])
continue;
out[tmp].pos = tp;
out[tmp++].val = getvalue(tp);
}
}
for (int i = row; i < row + 1; i++){ //计算每一段第一个点所在行的下一行的第一个点转化后的值
for (int j = 0; j < 1; j++){
int tp = i * width + j + 1;
if (i<0 || j>width || tp>num[cnt - 1])
continue;
out[tmp].pos = tp;
out[tmp++].val = getvalue(tp);
}
}
pos += in[k][1];
}
for (int i = (num[cnt - 1] - 1) / width; i < (num[cnt - 1] - 1) / width + 1; i++){
for (int j = 0; j < 1; j++){ //计算图的左下角点转化后的值
int tp = i*width + j + 1;
if (i<0 || j>width || tp>num[cnt - 1])
continue;
out[tmp].pos = tp;
out[tmp++].val = getvalue(tp);
}
}
sort(out, out + tmp); //按照所计算的点的序号排序
cout << width << endl; //开始输出
int temp = out[0].val;
int tpos = 1;
for (int i = 1; i < tmp; i++){
if (out[i].val == temp)
continue;
cout << temp << " " << out[i].pos - tpos << endl;
temp = out[i].val;
tpos = out[i].pos;
}
cout << temp << " " << num[cnt - 1] + 1 - tpos << endl;
cout << "0 0" << endl;
}
cout << "0" << endl;
}