\(\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. java 方法 compareTo()的正确使用

    总结:(1)如果比较的是数字 则结果大于则为1 等于则为0 小于则为-1(2)如果比较的是字符[串] 则按照从左到右排序找对应不一样的字符第一个字符, 然后将字符装对应的ASCLL码数字,做减法运算, ...

  2. java 多态 总结

    1.前言 引用教科书解释: 多态是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作. 通俗来说: 总结:多态的抽象类与接口有点相似: 父类不需要具体实现方 ...

  3. Pandas系列(十八)- 多级索引

    多级索引 多级索引(也称层次化索引)是pandas的重要功能,可以在Series.DataFrame对象上拥有2个以及2个以上的索引.实质上,单级索引对应Index对象,多级索引对应MultiInde ...

  4. WebLogic任意文件上传漏洞(CVE-2019-2725)

    一,漏洞介绍 1.1漏洞简介 Oracle weblogic反序列化远程命令执行漏洞,是根据weblogic的xmldecoder反序列化漏洞,只是通过构造巧妙的利用链可以对Oracle官方历年来针对 ...

  5. POJ prime distance

    https://oj.shiyancang.cn/Problem/781.html 素数距离,数据范围21亿,如果用素数筛存,并且进行做的话,按照x/lnx计算会是一个非常恐怖的复杂度.确定要做什么, ...

  6. NPOI处理Excel

    using NPOI; using NPOI.XSSF.UserModel; using NPOI.SS.UserModel; using NPOI.HSSF.UserModel; NPOI.SS.U ...

  7. C++ 基本类型的大小

    C++的基本类型: char bool (unsigned) short (int) (unsigned) int (unsigned) long (int) (unsigned) long long ...

  8. CAS基础

    有锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问题. (2)一个线程持有锁会导致其它所有需要此锁的线程挂起. (3)如果一个优先级高的线程等待一 ...

  9. mysql表设计原则

    0.三大范式及反范式 ◆ 第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列.  ◆ 第二范式(2NF):首先是 1NF,另外包含两部分内容,一是表必须有一个主键:二是没有包含在主键中的 ...

  10. python全局解释器GIL锁(-死锁)

    目录 一:Python中的GIL锁 1.GIL介绍 2.GIL的作用 3.cpython 4.内存管理>>>垃圾回收机制 二:全局解释器锁GIL 1.GIL特点 三:计算密集型与IO ...