zoukankan      html  css  js  c++  java
  • 钻石游戏——论预处理的重要性

    钻石游戏 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-

  • 相关阅读:
    js 报Unexpected token }
    c# 预览服务器文件
    js下载文件并修改文件名称
    js 自定义右键
    js 加载图片
    随笔1
    随笔
    php curl 发送post请求带参数
    laravel 数据库事务
    an't connect to local MySQL server through socket '/tmp/mysql.sock'
  • 原文地址:https://www.cnblogs.com/cain-/p/7388189.html
Copyright © 2011-2022 走看看