N×M的棋盘(M,N<=500)中,每个格子有一个颜色(颜色数1~9)

P次操作(P<=1000),每次给出两个相邻的位置(保证颜色不同,两个格子有一条公共边),把这两个格子交换。

定义每次交换的分值为:通过这次交换能够形成的最大矩形的面积。

求每次操作后的分值。

【题解】

      ①预处理类似于悬线法,维护u,d,l,r

      ②由于需要包含当前点,因此可以向两侧维护单调递减序列(大了就削掉)。

      ③维护双指针,根据单调性,可以O(n)推出最大的矩形面积。

(ZJ亲手绘制)

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 505
using namespace std;
int mp[MAXN][MAXN];
int Up[MAXN][MAXN],Down[MAXN][MAXN],Left[MAXN][MAXN],Right[MAXN][MAXN];
int n,m;
void calculation_row(int i){
for(int j=1;j<=m;j++)
if(j==1||mp[i][j-1]!=mp[i][j]) Left[i][j]=1;
else Left[i][j]=Left[i][j-1]+1;
for(int j=m;j>=1;j--)
if(j==m||mp[i][j+1]!=mp[i][j]) Right[i][j]=1;
else Right[i][j]=Right[i][j+1]+1;
}
void calculation_column(int j){
for(int i=1;i<=n;i++)
if(i==1||mp[i-1][j]!=mp[i][j]) Up[i][j]=1;
else Up[i][j]=Up[i-1][j]+1;
for(int i=n;i>=1;i--)
if(i==n||mp[i+1][j]!=mp[i][j]) Down[i][j]=1;
else Down[i][j]=Down[i+1][j]+1;
}
void readin(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mp[i][j]);
for(int i=1;i<=n;i++)
calculation_row(i);
for(int j=1;j<=m;j++)
calculation_column(j);
}
int get_lr(int x,int y,int t[MAXN][MAXN]){
static int h[MAXN],v[MAXN],cnt,p,ans,now;
ans=t[x][y];
cnt=0; p=1; now=t[x][y]; h[++cnt]=t[x][y]; v[cnt]=1;
for(int i=x-1;i>=x-Up[x][y]+1;i--){
if(t[i][y]<h[cnt]) h[++cnt]=t[i][y];
v[cnt]=x-i+1;
}
for(int i=x+1;i<=x+Down[x][y]-1;i++){
now=min(now,t[i][y]);
while(p+1<=cnt&&h[p+1]>=now) p++;
ans=max(ans,(i-x+v[p])*now);
}
cnt=0; p=1; now=t[x][y]; h[++cnt]=t[x][y]; v[cnt]=1;
for(int i=x+1;i<=x+Down[x][y]-1;i++){
if(t[i][y]<h[cnt]) h[++cnt]=t[i][y];
v[cnt]=i-x+1;
}
for(int i=x-1;i>=x-Up[x][y]+1;i--){
now=min(now,t[i][y]);
while(p+1<=cnt&&h[p+1]>=now) p++;
ans=max(ans,(x-i+v[p])*now);
}
return ans;
}
int get_ud(int x,int y,int t[MAXN][MAXN]){
static int h[MAXN],v[MAXN],cnt,p,ans,now;
ans=t[x][y];
cnt=0; p=1; now=t[x][y]; h[++cnt]=t[x][y]; v[cnt]=1;
for(int j=y-1;j>=y-Left[x][y]+1;j--){
if(t[x][j]<h[cnt]) h[++cnt]=t[x][j];
v[cnt]=y-j+1;
}
for(int j=y+1;j<=y+Right[x][y]-1;j++){
now=min(now,t[x][j]);
while(p+1<=cnt&&h[p+1]>=now) p++;
ans=max(ans,(j-y+v[p])*now);
}
cnt=0; p=1; now=t[x][y]; h[++cnt]=t[x][y]; v[cnt]=1;
for(int j=y+1;j<=y+Right[x][y]-1;j++){
if(t[x][j]<h[cnt]) h[++cnt]=t[x][j];
v[cnt]=j-y+1;
}
for(int j=y-1;j>=y-Left[x][y]+1;j--){
now=min(now,t[x][j]);
while(p+1<=cnt&&h[p+1]>=now) p++;
ans=max(ans,(y-j+v[p])*now);
}
return ans;
}
void printmap(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
printf("%d ",mp[i][j]);
printf("\n");
} }
void work(){
int k,x1,x2,y1,y2,ans;
scanf("%d",&k);
while(k--){
ans=0;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
swap(mp[x1][y1],mp[x2][y2]);
calculation_row(x1);
calculation_column(y1);
if(x1==x2){
calculation_column(y2);
if(y1>y2) swap(y1,y2);
ans=max(ans,get_lr(x1,y1,Left));
ans=max(ans,get_lr(x2,y2,Right));
}
else{
calculation_row(x2);
if(x1>x2) swap(x1,x2);
ans=max(ans,get_ud(x1,y1,Up));
ans=max(ans,get_ud(x2,y2,Down));
}
printf("%d\n",ans);
//printmap();
}
}
int main(){
//freopen("2050.in","r",stdin);
readin();
work();
return 0;
}//*ZJ

.

【ZJ选讲·钻石游戏】的更多相关文章

  1. 【ZJ选讲·画山】

    给出一张纸(N × M),你要在上面画山,但不能画出界(N,M<=100) Like this: 起点为(0,0),终点为(N,0) 给出w种线段画法(x,y),表示用了这种画法后,笔迹末 ...

  2. 【ZJ选讲·字符串折叠】

    给一个字符串(len<=100) 把这个字符串折叠(就是压缩) 记 X(子串) 表示重复 X次该子串 比如 3(orz)  orzorzorz  来点神奇例子: AAAAAAAAAA ...

  3. 【ZJ选讲·压缩】

    给一个由小写字母组成的字符串(len<=50) 我们可以用一种简单的方法来压缩其中的重复信息. 用M,R两个大写字母表示压缩信息 M标记重复串的开始, R表示后面的一段字符串重复从上一个 ...

  4. 【ZJ选讲·调整】

    给出n个点,m条有向边(带正权),起点S,终点T.(n<=2000,m<=30000) 再给出一个k,表示可以把最多k条边的权值调整为任意非负整数.(k<=100) 问是否可以通 ...

  5. 【ZJ选讲·BZOJ 5073】

    小A的咒语 给出两个字符串A,B (len<=105) 现在可以把A串拆为任意段,然后取出不超过 x 段,按在A串中的前后顺序拼接起来 问是否可以拼出B串. [题解]       ①如果遇 ...

  6. 【ZJ选讲·BZOJ 5071】

    小A的数字 有一串数字A1 ,A2,--,An,每次可以进行如下骚操作: 选择一个数字i,将(Ai-1,Ai,Ai+1)变为(Ai-1+Ai,-Ai,Ai+1+Ai), (特别地,若i=N,则( ...

  7. 2019暑期金华集训 Day6 杂题选讲

    自闭集训 Day6 杂题选讲 CF round 469 E 发现一个数不可能取两次,因为1,1不如1,2. 发现不可能选一个数的正负,因为1,-1不如1,-2. hihoCoder挑战赛29 D 设\ ...

  8. DP选讲

    $DP$选讲直接上题吧放个题单[各省省选DP](https://www.luogu.com.cn/training/151079)$P5322[BJOI2019]$排兵布阵一眼题,考虑$dp[i][j ...

  9. PJ可能会用到的动态规划选讲-学习笔记

    PJ可能会用到的动态规划选讲-学习笔记 by Pleiades_Antares 难度和速度全部都是按照普及组来定的咯 数位状压啥就先不讲了 这里主要提到的都是比较简单的DP 一道思维数学巧题(补昨天) ...

随机推荐

  1. Nginx反向代理 Laravel获取真实IP地址(PHP)

    使用VUE前后端分离开发 后端使用Laravel  想要获取到用户的真实IP地址 因为分离开发不同源跨域问题 所以只能进行前端Nginx反向代理 location /api { rewrite ^/a ...

  2. YII2.0学习一 Advanced 模板安装

    下载github上的完事安装包(本机环境使用Composer安装非常慢) https://github.com/yiisoft/yii2-app-advanced 解压到文件目录 wwwroot/sh ...

  3. Laravel -- Blade模板

    {{--流程控制--}} @if($name == '1') this is 1 @elseif($name == '2') this.is 2 @else who am i? @endif @for ...

  4. Hadoop(4)--Hbase

    Hadoop 其它组成角色介绍--Hbase 在apache的官方网站上,对于Hbase的定义是他是Hadoop的第一个分布式.可扩展的大数据存储的数据库,他的目标是将非常大的表托管到一个集群中进行相 ...

  5. 4.《python自省指南》学习

    前言   前面几篇博客我都是通过python自省来分析代码并试图得出结论.当然,仅仅通过自省能解决的问题有限,但遇到问题还是不自主的去用这个功能,觉得对于认识代码的含义还是有一定帮助的.而这些自省的知 ...

  6. python中协程实现的本质以及两个封装协程模块greenle、gevent

    协程 协程,又称微线程,纤程.英文名Coroutine. 协程是啥 协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源). 为啥说它是一个执行单元,因为 ...

  7. Python Web开发中,WSGI协议的作用和实现原理详解

    首先理解下面三个概念: WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web server ...

  8. 通过SVI实现VLAN间通信

    两个不同网段的计算机与三层交换机直连,通过SVI实现VLAN间通信vlan 1 //几个不同网段就创建几个VLANvlan 2 int f0/1 //划分VLANswitchport mode acc ...

  9. mybatis 打印SQL

    如果使用的是application.properties文件,加入如下配置: #打印SQL logging.level.com.jn.ssr.supererscuereporting.dao=debu ...

  10. python2.7入门---函数

        不是说现在的高级程序员都是秉承着用最少的代码实现功能么,那么,怎么才能使代码少呢?好吧,不装哔~~~了,这一波操作我说不来,咱们直接来看内容.首先,函数是组织好的,可重复使用的,用来实现单一, ...