【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 一道思维数学巧题(补昨天) ...
随机推荐
- Promise 的基础用法
Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案–回调函数和事件--更合理和更强大.它由社区最早提出和实现,ES6将其写进了语言标准,统一了语法,原生提供了Promi ...
- elasticsearch 5.x 系列之六 文档索引,更新,查询,删除流程
一.elasticsearch index 索引流程 步骤: 客户端向Node1 发送索引文档请求 Node1 根据文档ID(_id字段)计算出该文档应该属于shard0,然后请求路由到Node3的P ...
- python面向对象-cs游戏示例
#!/usr/local/bin/python3 # -*- coding:utf-8 -*- class Role(object): n = 123 # 类变量 name = "我是类na ...
- hive的desc命令
desc命令 desc 命令是为了展示hive表格的内在属性.例如列名,data_type,存储位置等信息.这个命令常常用在我们对hive表格观察之时,我们想要知道这个hive各个列名(基于这些具体列 ...
- P1396 营救(最小瓶颈路)
题目描述 “咚咚咚……”“查水表!”原来是查水表来了,现在哪里找这么热心上门的查表员啊!小明感动的热泪盈眶,开起了门…… 妈妈下班回家,街坊邻居说小明被一群陌生人强行押上了警车!妈妈丰富的经验告诉她小 ...
- 【多线程】 Task
[多线程] Task 一. 常用方法: 1. ContinueWith : 当前 Task 完成后, 执行传入的 Task 2. Delay : 创建一个等待的 Task,只有在调用 Wait 方法时 ...
- safari 移动下开启 滚定回弹
-webkit-overflow-scrolling : touch;
- json与python解析
1.json.dumps 将 Python 对象编码成 JSON 字符串 json.loads 将已编码的 JSON 字符串解码为 Python 对象 2.json.dump() ...
- linux学习笔记---学习总结②
table ----> 展示数据 table --->表格 border cellspacing cellpadding width height tr --->行 align th ...
- 维特比算法(Viterbi)及python实现样例
维特比算法(Viterbi) 维特比算法 维特比算法shiyizhong 动态规划算法用于最可能产生观测时间序列的-维特比路径-隐含状态序列,特别是在马尔可夫信息源上下文和隐马尔科夫模型中.术语“维特 ...