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