\(\mathcal{Description}\)

  Link.

  给定一张 \(n\times m\) 的表格,每个格子上写有一个小写字母。求其中长宽至少为 \(2\),且边界格子上字母相同的矩形个数。

  \(n,m\le2\times10^3\)。

\(\mathcal{Solution}\)

  可以感知到这是道分治题。

  不妨设当前处理左上角 \((u,l)\),右下角 \((d,r)\) 的矩形内的所有答案,且 \(d-u>r-l\)。那么取行的一半 \(p=\lfloor\frac{u+d}{2}\rfloor\),尝试求出所有在矩形内且跨过 \(p\) 这条水平直线的矩形数量。对于 \(p\) 上的每个点 \((p,i)\),预处理出其 向上/向下 走到的同种格子中,有多少个能 向左/向右 走 \(x\) 步,然后枚举矩形跨过 \(p\) 的两个位置 \(i,j\),讨论 \(i,j\) 向上/向下 能走步数的大小关系,利用预处理的信息计算答案。

  这样每层做到 \(\mathcal O((d-u)(r-l))\),所以总复杂度 \(\mathcal O(nm(\log n+\log m))\)。

\(\mathcal{Code}\)

/*~Rainybunny~*/

#include <bits/stdc++.h>

#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i ) typedef long long LL; inline int imin( const int a, const int b ) { return a < b ? a : b; }
inline int imax( const int a, const int b ) { return a < b ? b : a; } const int MAXN = 2e3;
int n, m;
int up[MAXN + 5][MAXN + 5], dn[MAXN + 5][MAXN + 5];
int le[MAXN + 5][MAXN + 5], ri[MAXN + 5][MAXN + 5];
int sum[MAXN + 5][MAXN + 5][4];
char grid[MAXN + 5][MAXN + 5];
LL ans; inline void solve( const int u, const int d, const int l, const int r ) {
if ( u + 1 > d || l + 1 > r ) return ; if ( d - u > r - l ) {
int mr = u + d >> 1, lr = r - l + 1;
solve( u, mr, l, r ), solve( mr + 1, d, l, r ); rep ( i, l, r ) rep ( j, 0, lr ) {
sum[i][j][0] = sum[i][j][1] = sum[i][j][2] = sum[i][j][3] = 0;
}
rep ( i, l, r ) {
rep ( j, imax( u, mr - up[mr][i] + 1 ),
imin( d, mr + dn[mr][i] - 1 ) ) {
++sum[i][imin( ri[j][i], lr )][( mr < j ) * 2];
++sum[i][imin( le[j][i], lr )][( mr < j ) * 2 + 1];
}
per ( j, lr - 1, 0 ) rep ( k, 0, 3 ) {
sum[i][j][k] += sum[i][j + 1][k];
}
}
rep ( i, l, r ) rep ( j, i + 1, r ) {
if ( grid[mr][i] == grid[mr][j] ) {
ans += 1ll *
( up[mr][i] < up[mr][j] ?
sum[i][j - i + 1][0] : sum[j][j - i + 1][1] ) *
( dn[mr][i] < dn[mr][j] ?
sum[i][j - i + 1][2] : sum[j][j - i + 1][3] );
}
}
} else {
int mc = l + r >> 1, ud = d - u + 1;
solve( u, d, l, mc ), solve( u, d, mc + 1, r ); rep ( i, u, d ) rep ( j, 0, ud ) {
sum[i][j][0] = sum[i][j][1] = sum[i][j][2] = sum[i][j][3] = 0;
}
rep ( i, u, d ) {
rep ( j, imax( l, mc - le[i][mc] + 1 ),
imin( r, mc + ri[i][mc] - 1 ) ) {
++sum[i][imin( dn[i][j], ud )][( mc < j ) * 2];
++sum[i][imin( up[i][j], ud )][( mc < j ) * 2 + 1];
}
per ( j, ud - 1, 0 ) rep ( k, 0, 3 ) {
sum[i][j][k] += sum[i][j + 1][k];
}
}
rep ( i, u, d ) rep ( j, i + 1, d ) {
if ( grid[i][mc] == grid[j][mc] ) {
ans += 1ll *
( le[i][mc] < le[j][mc] ?
sum[i][j - i + 1][0] : sum[j][j - i + 1][1] ) *
( ri[i][mc] < ri[j][mc] ?
sum[i][j - i + 1][2] : sum[j][j - i + 1][3] );
}
}
}
} int main() {
scanf( "%d %d", &n, &m );
rep ( i, 1, n ) scanf( "%s", grid[i] + 1 ); rep ( i, 1, n ) rep ( j, 1, m ) {
le[i][j] = grid[i][j] == grid[i][j - 1] ? le[i][j - 1] + 1 : 1;
up[i][j] = grid[i][j] == grid[i - 1][j] ? up[i - 1][j] + 1 : 1;
}
per ( i, n, 1 ) per ( j, m, 1 ) {
ri[i][j] = grid[i][j] == grid[i][j + 1] ? ri[i][j + 1] + 1 : 1;
dn[i][j] = grid[i][j] == grid[i + 1][j] ? dn[i + 1][j] + 1 : 1;
} solve( 1, n, 1, m );
printf( "%lld\n", ans );
return 0;
}

Solution -「Gym 102956F」Border Similarity Undertaking的更多相关文章

  1. Solution -「Gym 102956F」Find the XOR

    \(\mathcal{Description}\)   Link.   给定 \(n\) 个点 \(m\) 条边的连通无向图 \(G\),边有边权.其中 \(u,v\) 的距离 \(d(u,v)\) ...

  2. Solution -「Gym 102979E」Expected Distance

    \(\mathcal{Description}\)   Link.   用给定的 \(\{a_{n-1}\},\{c_n\}\) 生成一棵含有 \(n\) 个点的树,其中 \(u\) 连向 \([1, ...

  3. Solution -「Gym 102979L」 Lights On The Road

    \(\mathcal{Description}\)   Link.   给定序列 \(\{w_n\}\),选择 \(i\) 位置的代价为 \(w_i\),要求每个位置要不被选择,要不左右两个位置至少被 ...

  4. Solution -「Gym 102956B」Beautiful Sequence Unraveling

    \(\mathcal{Description}\)   Link.   求长度为 \(n\),值域为 \([1,m]\) 的整数序列 \(\lang a_n\rang\) 的个数,满足 \(\not\ ...

  5. Solution -「Gym 102956A」Belarusian State University

    \(\mathcal{Description}\)   Link.   给定两个不超过 \(2^n-1\) 次的多项式 \(A,B\),对于第 \(i\in[0,n)\) 个二进制位,定义任意一个二元 ...

  6. Solution -「Gym 102798I」Sean the Cuber

    \(\mathcal{Description}\)   Link.   给定两个可还原的二阶魔方,求从其中一个状态拧到另一个状态的最小步数.   数据组数 \(T\le2.5\times10^5\). ...

  7. Solution -「Gym 102798K」Tree Tweaking

    \(\mathcal{Description}\)   Link.   给定排列 \(\{p_n\}\),求任意重排 \(p_{l..r}\) 的元素后,将 \(\{p_n\}\) 依次插入二叉搜索树 ...

  8. Solution -「Gym 102798E」So Many Possibilities...

    \(\mathcal{Description}\)   Link.   给定非负整数序列 \(\{a_n\}\) 和 \(m\),每次随机在 \(\{a\}\) 中取一个非零的 \(a_i\)(保证存 ...

  9. Solution -「Gym 102759I」Query On A Tree 17

    \(\mathcal{Description}\)   Link.   给定一棵含 \(n\) 个结点的树,结点 \(1\) 为根,点 \(u\) 初始有点权 \(a_u=0\),维护 \(q\) 次 ...

随机推荐

  1. LINUX学习-Mysql集群-主从服务器备份

    一.Mysql主从集群备份. 1.准备两台主机 主服务器:192.168.88.20和从服务器:192.168.88.30 2.分别安装mysql yum -y -install mysql mysq ...

  2. vue项目配置及代理解决跨域

    axios数据请求 1.下载模块:npm install axios 2.axios特点: 1.支持在浏览器当中发起XMLHttpRequest请求 2.支持Promise 3.自动转换json数据 ...

  3. .NET Core 利用委托进行动态流程组装

    引言 在看.NET Core 源码的管道模型中间件(Middleware)部分,觉得这个流程组装,思路挺好的,于是就分享给大家.本次代码实现就直接我之前写的动态代理实现AOP的基础上直接改了,就不另起 ...

  4. 端口状态 LISTENING、ESTABLISHED、TIME_WAIT及CLOSE_WAIT详解,以及三次握手四次挥手,滑动窗口(整理转发)

    网上查了一下端口状态的资料,我下面总结了一下,自己学习学习: TCP状态转移要点 TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死 ...

  5. Typora图床

    Typora图床 Typora+PicGo+Gitee(码云)实现高效Markdown图床 typora是我最早接触的markdown格式的轻文本编辑器,因为我是计算机专业,所以平常记笔记会有代码块, ...

  6. Android官方文档翻译 十四 3.2Supporting Different Screens

    Supporting Different Screens 支持不同的屏幕 This lesson teaches you to 这节课教给你 Create Different Layouts 创建不同 ...

  7. Visual Studio 2015 MFC之Button颜色变化-断点调试(Debug)

    软件开发,对自己的程序进行调试很重要,本次文章在上一边随笔的基础上,介绍一下Button控件做显示灯的用法,Button控件的添加和变量设置等可以参考下面的的链接:Visaul Studio 2015 ...

  8. Python中hash加密

    目录 简介 概念 特点 hash有哪些 算法碰撞 加盐防碰撞 加密 hashlib 主要方法 特有方法 使用方法 加盐 crypt 主要方法 使用说明 应用 密码加密 应用一致性校验 简介 概念 散列 ...

  9. MyCms 自媒体 CMS 系统 v2.6,SEO 优化升级

    MyCms 是一款基于Laravel开发的开源免费的自媒体博客CMS系统,助力开发者知识技能变现. MyCms 基于Apache2.0开源协议发布,免费且不限制商业使用,欢迎持续关注我们. V2.6 ...

  10. 『无为则无心』Python基础 — 41、Python中文件的读写操作(一)

    目录 1.文件操作步骤 2.文件的读写操作 (1)文件的打开 (2)打开文件模式 (3)获取一个文件对象 (4)关于文件路径 1.文件操作步骤 当我们要读取或者写入文件时,我们需要打开文件,在操作完毕 ...