钻石游戏——论预处理的重要性

钻石游戏 diamond

题目描述:

一个 M 行 N 列的棋盘,里面放了 M*N 个各种颜色的钻石。每一次你可以选择任意两个相邻的颜色不同的钻石,进行交换。两个格子相邻的定义是两个格子有一条公共边。每次交换的分值为通过这次交换后能够形成的最大矩形的面积。具体请见样例,跟传统的钻石游戏不太一样的是,交换后钻石不会消除。
现在告诉你每一次操作,请输出每一次所能得到的分值。

输入格式:

第一行二个整数 M,N。接下来 M 行 N 列,表示
第 I 行第 J 列的钻石的颜色(1~9)
第 M+2 行有一个正整数 P,表示钻石交换的次数
接下来 P 行,每行四个正整数 x1,y1,x2,y2
(1<=x1,x2<=M,1<=y1,y2<=N)表示交换(x1,y1)和(x2,y2)的钻石。
保证(x1,y1),(x2,y2)的颜色不相同。并且其必定相邻。

输出格式:

P 行,输出每次交换得到的分值。

样例输入:

4 5
1 1 1 3 4
1 1 2 1 2
1 1 1 2 2
3 3 3 4 4
2 
2 3 2 4
1 4 1 5 

样例输出:

9
1

提示:

对于第一个操作
1 1 1 3 4
1 1 1 2 2
1 1 1 2 2
3 3 3 4 4


1 1 1 3 4
1 1 2 1 2
1 1 1 2 2
3 3 3 4 4


因为 9>4,因而形成的最大矩形为 9
40%的数据,M,N<=50,P<=1000
100%的数据,M,N<=500,P<=1000
T2:Mult

时间限制:1000ms
空间限制:256MByte

这个题目吧……呆滞大佬AC了!好好好,不说闲话。这个题目的话有一个比较坑的点就是,矩阵的形成,一定是因为交换形成的矩阵,而不是遍历整张图查看最大的矩阵……没错,刚开始的时候是注意到了,但是后来还是背坑了。原本程序的话骗骗分还是可以的,但是背坑了之后就爆零了。这题的正确解法就是各种预处理,开四个矩阵,分别表示从四个方向上的一条直线之前有多少颜色相同的格子。然后每次更新,相比更新的操作,每次进行扫描慢了很多。然后……我就要慢慢地写代码了……

没错……当你看到这行字的时候已经是第二天了……我用了一个晚上外加早上的两个半小时终于把这个鬼东西改完……这个东西主要看细不细心……先贴代码吧……

#include<bits/stdc++.h>
using namespace std;
int mp[505][505],mp1[505][505],mp2[505][505],mp3[505][505],mp4[505][505],mp5[505][505];
int n,m,chan;
void updata(int x1,int y1,int x2,int y2){
	if (x1==x2){
		for (int i=1; i<=m; i++)
			if (mp[x1][i-1]==mp[x1][i]) mp2[x1][i]=mp2[x1][i-1]+1;
			else mp2[x1][i]=1;
		for (int i=m; i>=1; i--)
			if (mp[x1][i+1]==mp[x1][i]) mp3[x1][i]=mp3[x1][i+1]+1;
			else mp3[x1][i]=1;
		for (int i=1; i<=n; i++){
			if (mp[i][y1]==mp[i-1][y1]) mp1[i][y1]=mp1[i-1][y1]+1;
			else mp1[i][y1]=1;
			if (mp[i][y2]==mp[i-1][y2]) mp1[i][y2]=mp1[i-1][y2]+1;
			else mp1[i][y2]=1;
		}
		for (int i=n; i>=1; i--){
			if (mp[i][y1]==mp[i+1][y1]) mp4[i][y1]=mp4[i+1][y1]+1;
			else mp4[i][y1]=1;
			if (mp[i][y2]==mp[i+1][y2]) mp4[i][y2]=mp4[i+1][y2]+1;
                        //这里的mp4[i][y2]=mp4[i+1][y2]+1;之前打成了mp4[i][y2]==mp4[i+1][y2]+1;
                        //死活找不出来
			else mp4[i][y2]=1;
		}
	}
	else if (y1==y2){
		for (int i=1; i<=n; i++)
			if (mp[i][y1]==mp[i-1][y1]) mp1[i][y1]=mp1[i-1][y1]+1;
			else mp1[i][y1]=1;
		for (int i=n; i>=1; i--)
			if (mp[i][y1]==mp[i+1][y1]) mp4[i][y1]=mp4[i+1][y1]+1;
			else  mp4[i][y1]=1;
		for (int i=1; i<=m; i++){//这里的循环之前想要减少一点……结果……减错了
			if (mp[x1][i-1]==mp[x1][i]) mp2[x1][i]=mp2[x1][i-1]+1;
			else mp2[x1][i]=1;
			if (mp[x2][i-1]==mp[x2][i]) mp2[x2][i]=mp2[x2][i-1]+1;
			else mp2[x2][i]=1;	
		}
		for (int i=m; i>=1; i--){
			if (mp[x1][i+1]==mp[x1][i]) mp3[x1][i]=mp3[x1][i+1]+1;
			else mp3[x1][i]=1;
			if (mp[x2][i+1]==mp[x2][i]) mp3[x2][i]=mp3[x2][i+1]+1;
			else mp3[x2][i]=1;
		}	
	}
}
int main(){
	cin>>n>>m;
	for (int i=1; i<=n; i++){
		for (int l=1; l<=m; l++){
			cin>>mp[i][l];
			if (mp[i-1][l]==mp[i][l]) mp1[i][l]=mp1[i-1][l]+1;
			else mp1[i][l]=1;
			if (mp[i][l-1]==mp[i][l]) mp2[i][l]=mp2[i][l-1]+1;
			else mp2[i][l]=1;
		}
	}
	for (int i=n; i>=1; i--){
		for (int l=m; l>=1; l--){
			if (mp[i][l+1]==mp[i][l]) mp3[i][l]=mp3[i][l+1]+1;
			else mp3[i][l]=1;
			if (mp[i+1][l]==mp[i][l]) mp4[i][l]=mp4[i+1][l]+1;
			else mp4[i][l]=1;
		}
	}
	cin>>chan;
	for (int i=1; i<=chan; i++){
		int x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;
		swap(mp[x1][y1],mp[x2][y2]);
		updata(x1,y1,x2,y2);
		if (x1==x2){
			int pos=min(y1,y2),minau=1e7,minad=1e7,maxn=-1;
			while (mp[x1][pos]==mp[x1][min(y1,y2)] && pos>=1){
//				mina=min(mina,mp1[x1][pos]+mp4[x1][pos]-1);
//                              这里是一个非常关键的错误,关系到理解题意。
//                              大致意思就是如果是左右交换就往左右扫,用这一条路最小高度乘长度更新最大面积
//                              如果上下更新就往上下扫,用最小宽度乘高度更新最大面积
//                              原本我是非常naive地算最小高度这个东西的,就是上加下-1,但是!这样是错的
//                              应该分别用上和下的最小值来更新最小高度,而不是看总和。。。
				minau=min(minau,mp1[x1][pos]);
				minad=min(minad,mp4[x1][pos]);
				maxn=max(maxn,(min(y1,y2)-pos+1)*(minau+minad-1));
				pos--;
			}
			pos=max(y1,y2);minau=1e7;minad=1e7;
			while (mp[x1][pos]==mp[x1][max(y1,y2)] && pos<=m){
//				mina=min(mina,mp1[x1][pos]+mp4[x1][pos]-1);
				minau=min(minau,mp1[x1][pos]);
				minad=min(minad,mp4[x1][pos]);
				maxn=max(maxn,(pos-max(y1,y2)+1)*(minau+minad-1));
				pos++;
			}
			cout<<maxn<<endl;
		}
		else if (y1==y2){
			int pos=min(x1,x2),minal=1e8,minar=1e8,maxn=-1;
			while (mp[pos][y1]==mp[min(x1,x2)][y1] && pos>=1){
//				mina=min(mina,mp2[pos][y1]+mp3[pos][y1]-1);
				minal=min(minal,mp2[pos][y1]);
				minar=min(minar,mp3[pos][y1]);
				maxn=max(maxn,(min(x1,x2)-pos+1)*(minal+minar-1));
				pos--;
			}
			pos=max(x1,x2);minal=1e8;minar=1e8;
			while (mp[pos][y1]==mp[max(x1,x2)][y1] && pos<=n){
//				mina=min(mina,mp2[pos][y1]+mp3[pos][y1]-1);
				minal=min(minal,mp2[pos][y1]);
				minar=min(minar,mp3[pos][y1]);
				maxn=max(maxn,(pos-max(x1,x2)+1)*(minal+minar-1));
				pos++;
			}
			cout<<maxn<<endl;
		}
	}
	return 0;
}

我的内心几乎是崩溃的……这个鬼东西弄了我好久……最终终于AC了……感到内心十分的欣慰啊……原本想……这几天都没有写博客,来写一些补偿一下……这个补偿……是真的全补完了……破事水……

还有……最近久久去军训了……希望能够活着回来吧……还有希望自己还能够活下去……要坚强……

made by cain-

posted @ 2017-08-18 10:29  |斗蜂|  阅读(265)  评论(0编辑  收藏  举报