【ZJ选讲·钻石游戏】
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选讲·钻石游戏】的更多相关文章
- 【ZJ选讲·画山】
给出一张纸(N × M),你要在上面画山,但不能画出界(N,M<=100) Like this: 起点为(0,0),终点为(N,0) 给出w种线段画法(x,y),表示用了这种画法后,笔迹末 ...
- 【ZJ选讲·字符串折叠】
给一个字符串(len<=100) 把这个字符串折叠(就是压缩) 记 X(子串) 表示重复 X次该子串 比如 3(orz) orzorzorz 来点神奇例子: AAAAAAAAAA ...
- 【ZJ选讲·压缩】
给一个由小写字母组成的字符串(len<=50) 我们可以用一种简单的方法来压缩其中的重复信息. 用M,R两个大写字母表示压缩信息 M标记重复串的开始, R表示后面的一段字符串重复从上一个 ...
- 【ZJ选讲·调整】
给出n个点,m条有向边(带正权),起点S,终点T.(n<=2000,m<=30000) 再给出一个k,表示可以把最多k条边的权值调整为任意非负整数.(k<=100) 问是否可以通 ...
- 【ZJ选讲·BZOJ 5073】
小A的咒语 给出两个字符串A,B (len<=105) 现在可以把A串拆为任意段,然后取出不超过 x 段,按在A串中的前后顺序拼接起来 问是否可以拼出B串. [题解] ①如果遇 ...
- 【ZJ选讲·BZOJ 5071】
小A的数字 有一串数字A1 ,A2,--,An,每次可以进行如下骚操作: 选择一个数字i,将(Ai-1,Ai,Ai+1)变为(Ai-1+Ai,-Ai,Ai+1+Ai), (特别地,若i=N,则( ...
- 2019暑期金华集训 Day6 杂题选讲
自闭集训 Day6 杂题选讲 CF round 469 E 发现一个数不可能取两次,因为1,1不如1,2. 发现不可能选一个数的正负,因为1,-1不如1,-2. hihoCoder挑战赛29 D 设\ ...
- DP选讲
$DP$选讲直接上题吧放个题单[各省省选DP](https://www.luogu.com.cn/training/151079)$P5322[BJOI2019]$排兵布阵一眼题,考虑$dp[i][j ...
- PJ可能会用到的动态规划选讲-学习笔记
PJ可能会用到的动态规划选讲-学习笔记 by Pleiades_Antares 难度和速度全部都是按照普及组来定的咯 数位状压啥就先不讲了 这里主要提到的都是比较简单的DP 一道思维数学巧题(补昨天) ...
随机推荐
- Linux基础(02)、MTPutty安装和使用
准备工具 1. MTPutty的安装包 2. Putty.exe程序 作用:远程连接操作Centos 安装MTPutty 1.根据提示,一直下一步至下图:选择putty.exe文件的位置即可. 2.选 ...
- mysql日志管理#二进制日志详解
查看MySQL二进制文件中的内容有两种方式 mysqlbinlog SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row ...
- 腾讯招聘网数据爬取存入mongodb
#!/user/bin/env python3 # -*- coding: utf-8 -*- import requests from lxml import etree from math imp ...
- PublicCMS 网站漏洞 任意文件写入并可提权服务器权限
PublicCMS是目前网站系统中第一个采用JAVA架构 TOMCAT+Apcche+Mysql数据库架构的CMS网站,开源,数据承载量大,可以承载到上千万的数据量,以及用户的网站并发可达到上千万的P ...
- python爬虫 爬取steam热销游戏
好久没更新了啊...最近超忙 这学期学了学python 感觉很有趣 就写着玩~~~ 爬取的页面是:https://store.steampowered.com/search/?filter=globa ...
- 关于在各种int类型选择时的考虑
整数类型int在不同版本的c标准中不断丰富. 最初的K&R标准给出了int作为整数的基本类型,给出long.short.unsigned作为int的变式.在c90中又加入了signed. 在c ...
- mysql5.7.19安装报错 无法定位程序输入点
https://blog.csdn.net/t876587201/article/details/79503688
- SPFA算法(2) POJ 1511 Invitation Cards
原题: Invitation Cards Time Limit: 8000MS Memory Limit: 262144K Total Submissions: 31230 Accepted: ...
- CONCATENATE命令(文字列の結合)
CONCATENATE命令とは文字列の結合を行う命令である.文字列を扱うChar, Numeric, Dats, Time, Stringの変数で使用する事が可能だ.単純に文字列の結合のみを行う方法. ...
- 前端面试题目汇总摘录(JS 基础篇 —— 2018.11.02更新)
温故而知新,保持空杯心态 JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string type ...