万猪拱塔

  • description
  • solution
  • code

description

题目描述
小七养了很多头猪,它们分布在 n 行 m 列中,其中第 i 行第 j 列的猪圈养的是第 wi,jw_{i,j}wi,j​ 种猪。
小七有时会选择一个子矩形范围内的猪圈进行巡视,如果该子矩形包含 i 行 j 列 (1 ≤ i ≤ n; 1 ≤ j ≤ m),且子矩形内含有的猪种类编号最大值减去编号最小值恰好为 i × j - 1 ,则小七会获得 i × j 的愉悦值。
小七想知道,如果他将每个可能的子矩形都巡视一次,总共能获得多少愉悦值呢?你只需要输出答案对 998244353 取模的结果。

输入格式
输入文件 pig.in 包含 1 + n × m 行。
第一行输入两个正整数依次表示 n; m 。
接下来 n 行每行包含 m 个正整数,其中第 i 行的第 j 个正整数表示 wi;j 。

输出格式
输出文件 pig.out 包含一行,仅一个非负整数,表示答案对 998244353 取模
的结果。
样例输入

2 2
1 3
2 4

样例输出

12

样例解释
合法子矩形面积为 1 的有 4 个,面积为 2 的有 2 个,面积为 4 的有 1 个。
数据范围及约定

测试点编号 n × m 特殊性质
1 ∼ 2 ≤ 50
3 ∼ 6 ≤ 10^4
7 ∼ 12 ≤ 2 × 10^5 n = 1
13 ∼ 20 ≤ 2 × 10^5

对于 100% 的数据, 1 ≤ wi;j ≤ n × m ≤ 2 × 105 , 保证 wi;j 互不相同。

solution

先吐槽一下题目的 包含 真的是误导新青年!!

我以为是原矩阵的iii行jjj列,结果是选的矩阵重新编号后的iii行jjj列

实际上就是问多少矩阵内种类编号的极差等于矩阵行数乘列数再减一


应该不会有人只拿case 1~2的暴力吧

case 1~6 :枚举所选矩阵的左上角,求出以其右下方每一个点为矩阵右下角的种类最大值和最小值,可以通过扫一遍,然后行加一的时候继承上面一行信息,再操作

case 7~12n=1是一个一维问题,可以用线段树和单调栈解决

具体而言,枚举矩阵右端点rrr,如果区间[l,r][l,r][l,r]合法,则满足Maxl,r−Minl,r=r−l+1\text{Max}_{l,r}-\text{ Min}_{l,r}=r-l+1Maxl,r​− Minl,r​=r−l+1

对于每个lll的定义f[l]=Maxl,r−Minl,r+lf[l]=\text{Max}_{l,r}-\text{ Min}_{l,r}+lf[l]=Maxl,r​− Minl,r​+l,用线段树维护f[l]f[l]f[l]

因为种类互不相同,所以∀lf[l]≥r+1\forall_l f[l]\ge r+1∀l​f[l]≥r+1,只需要线段树维护f[l]f[l]f[l]的最小值,最小值个数,以及所有lll之和,就可以统计了,即(r+1)∗cnt−sum(r+1)*cnt-sum(r+1)∗cnt−sum

右端点移动111,用单调栈维护其影响的Maxl,r,Minl,r\text{Max}_{l,r},\text{Min}_{l,r}Maxl,r​,Minl,r​,在线段树上修改

Maxl,r\text{Max}_{l,r}Maxl,r​维护一个单调递减栈,Minl,r\text{Min}_{l,r}Minl,r​维护一个单调递增栈

case 13~20 :很不幸,一维的做法并不能处理二维情况

考虑另外一种nb的转化

考虑判定 权值 为[l,r][l,r][l,r]区间的点是否构成了一个矩阵,记这些格子的颜色为黑色,其余均为白色

将n×mn\times mn×m的猪圈算上周围一圈的空白边界,看成(n+1)×(m+1)(n+1)\times (m+1)(n+1)×(m+1)的猪圈

产生(n+1)×(m+1)(n+1)\times (m+1)(n+1)×(m+1)个2×22\times 22×2的小正方形猪圈(不能超出边界),标记在2×22\times 22×2这个矩阵的左上角

如果所有黑色格子能围成一个矩阵,当且仅当恰好有4个小猪圈只有1个黑点,没有任何一个小猪圈有3个黑点

不要急,仔细想想这句很妙的话,小猪圈是由其左上角表示的,只有围成的矩阵的四个顶点所在的小猪圈,只含这个顶点一个黑点

从小到大枚举权值rrr,定义F[l]F[l]F[l]为染黑权值为[l,r][l,r][l,r]的格子,其余格子为白色,小猪圈内有1/31/31/3个合格子的小猪圈数量

显然F[r]=4,F[l]≥4F[r]=4,F[l]\ge 4F[r]=4,F[l]≥4

这个时候可以利用一维的做法,线段树维护F[l]F[l]F[l]的最小值,最小值个数以及这些lll的和,贡献计算也是一样的

当rrr增加111的时候,只会影响444个2×22\times 22×2的矩阵(分别是r+1r+1r+1做左上角,右上角,左下角,右下角时的不同的444个小猪圈)

暴力修改即可——详见代码

最后就是这道题的天坑——卡常

必须开Ofast不然分竟然跟暴力差不多,快读快输,还有这种n×m≤2e5n\times m\le 2e5n×m≤2e5的必须卡着矩阵长相开数组的

这是什么jian题 好题,真的是好题!!

code

#pragma GCC optimize( "Ofast" )
#include <cstdio>
#define mod 998244353
#define maxn 200005
int Min[maxn << 2], cnt[maxn << 2], tag[maxn << 2];
long long sum[maxn << 2];
int ID[maxn];
int n, m, **w;#define Make( arr ) do { \arr = new int*[n + 3]; \for( int i = 0;i <= n + 2;i ++ ) arr[i] = new int[m + 3](); \
} while( false )inline void read( int &x ) {x = 0; char s = getchar();while( s < '0' or s > '9' ) s = getchar();while( '0' <= s and s <= '9' ) {x = ( x << 1 ) + ( x << 3 ) + ( s ^ 48 );s = getchar();}
}inline void write( int x ) {if( x >= 10 ) write( x / 10 );putchar( x % 10 ^ 48 );
}#define lson num << 1
#define rson num << 1 | 1
#define inf 0x3f3f3f3fint chkmin( int x, int y ) { return x < y ? x : y; }inline void pushup( int num ) {Min[num] = chkmin( Min[lson], Min[rson] );cnt[num] = sum[num] = 0;if( Min[num] == Min[lson] ) cnt[num] += cnt[lson], sum[num] += sum[lson];if( Min[num] == Min[rson] ) cnt[num] += cnt[rson], sum[num] += sum[rson];
}inline void build( int num, int l, int r ) {if( l == r ) { Min[num] = inf, cnt[num] = 1, sum[num] = l; return; }int mid = ( l + r ) >> 1;build( lson, l, mid );build( rson, mid + 1, r );pushup( num );
}inline void pushdown( int num ) {if( ! tag[num] ) return;Min[lson] += tag[num];tag[lson] += tag[num];Min[rson] += tag[num];tag[rson] += tag[num];tag[num] = 0;
}inline void modify( int num, int l, int r, int L, int R, int val ) {if( r < L or R < l ) return;if( L <= l and r <= R ) { Min[num] += val, tag[num] += val; return; }pushdown( num );int mid = ( l + r ) >> 1;modify( lson, l, mid, L, R, val );modify( rson, mid + 1, r, L, R, val );pushup( num );
}inline void modify( int r, int c, int Max, int opt ) {static int arr[4];if( ! ~opt ) {arr[0] = w[r][c], arr[1] = w[r][c + 1], arr[2] = w[r + 1][c], arr[3] = w[r + 1][c + 1];for( int i = 0;i < 3;i ++ )for( int j = 0;j < 3;j ++ )if( arr[j] > arr[j + 1] )    arr[j] ^= arr[j + 1] ^= arr[j] ^= arr[j + 1];}int ip = 0;for(;ip < 4 and arr[ip] <= Max;ip ++ );if( ip == 1 or ( ip > 1 and arr[ip - 1] ^ arr[ip - 2] ) )modify( 1, 1, n * m, ip == 1 ? 1 : arr[ip - 2] + 1, arr[ip - 1], opt );if( ip == 3 or ( ip > 3 and arr[ip - 3] ^ arr[ip - 4] ) )modify( 1, 1, n * m, ip == 3 ? 1 : arr[ip - 4] + 1, arr[ip - 3], opt );
}inline int mul( int x, int y ) { return 1ll * x * y % mod; }
inline int sub( int x, int y ) { return x - y < 0 ? x - y + mod : x - y; }
inline int add( int x, int y ) { return 1ll * x + y >= mod ? 1ll * x + y - mod : x + y; }int main() {freopen( "pig.in", "r", stdin );freopen( "pig.out", "w", stdout );scanf( "%d %d", &n, &m ); Make( w );for( int i = 0;i <= n + 1;i ++ ) w[i][0] = w[i][m + 1] = n * m + 1;for( int i = 1;i <= m;i ++ ) w[0][i] = w[n + 1][0] = n * m + 1;for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ )read( w[i][j] ), ID[w[i][j]] = ( i - 1 ) * m + j;build( 1, 1, n * m );int ans = 0;for( int i = 1;i <= n * m;i ++ ) {int r = ( ID[i] - 1 ) / m + 1, c = ID[i] - ( r - 1 ) * m;modify( 1, 1, n * m, i, i, -inf );for( int j = -1;j <= 0;j ++ )for( int k = -1;k <= 0;k ++ ) {modify( r + j, c + k, i - 1, -1 );modify( r + j, c + k, i, 1 );}if( Min[1] == 4 ) ans = add( ans, sub( mul( i + 1, cnt[1] ), sum[1] % mod ) );}write( ans );return 0;
}

[2020-09-11 CQBZ/HSZX多校联测 T3] 万猪拱塔(线段树+巧妙转化)相关推荐

  1. [2020-09-11 CQBZ/HSZX多校联测 T2] 泰拳警告(组合数+数学期望)

    泰拳警告 description solution code description 题目描述 小七擅长泰拳,某天他打算与小枣切磋拳技,一共需要进行 n 次比赛. 由于双方拳技难分上下,每场比赛小七获 ...

  2. [2021.1.27多校省选模拟10]跑步(线段树合并)

    [2021.1.27多校省选模拟10]跑步 经典的树上启发式合并题目,维护对应子树的从当前点到子树内一个节点这个链待定,其他部分已经确定的方案数,这个东西按照对应点到根节点的路径点权和为下标存在一个权 ...

  3. HDU 4893 Wow! Such Sequence!(2014年多校联合 第三场 G)(线段树)

    磨了一天的线段树,不能说完全搞清楚,只能说有一个大概的了解,靠着模板才把这道题A了,只能说太弱~~! 题意: 初始时有一字符串,全为0. 三种操作: 1 k d - add  把d加到第k个数上去 2 ...

  4. [2021-09-11 CQBZ/HSZX多校联考 T1] 茅山道术 (后缀和优化dp)

    茅山道术 description solution code description 题目描述 小七擅长茅山道术,有一天他发现了 n 个排成一行的宝石,其中第 i 个宝石 有一个颜色 ci . 小七决 ...

  5. 搜索引擎(2020.09.11)

    搜索引擎 国内方面 必应 百度 搜狗 海外方面 谷歌 雅虎 未完待续--

  6. 软件测评师知识点(2020.09.11)

    功能性的子特性 功能性包括的子特性有适合性.准确性.互操作性.安全保密性.功能依从性. 判定表 一个条件有两种判定:即真/假 一个条件两种,两个条件四种,三个条件八种 所以n个条件可以得到最多 2^n ...

  7. HDU多校4 - 6992 Lawn of the Dead(线段树+模拟)

    题目链接:点击查看 题目大意:给出一个 n∗mn*mn∗m 的矩阵,有 kkk 个点被 banbanban 掉了,现在从点 (1,1)(1,1)(1,1) 出发,只能向右或向下移动,问可以到达的点有多 ...

  8. 2021牛客暑期多校训练营7 B-xay loves monotonicity(线段树+不降子序列)

    P4198 楼房重建 线段树维护以某点为开头的最长不下降子序列 使用下面calc函数能够计算线段树u维护的区间中,以x为开头最长不下降子序列的个数. calc需要维护区间最值. template< ...

  9. 2021牛客暑期多校训练营7 F-xay loves trees(线段树+滑动窗口)

    F-xay loves trees 考虑在树1中满足条件的一些点,首先不难想到一定是一条链,其次如果点uuu被选择那么在树2以uuu为根的子树的点就禁止被选,于是只需区间+,然后查询区间最值是否存在& ...

最新文章

  1. e2e测试框架之Cypress
  2. Binder子系统之调试分析(一)
  3. Facebook押注VS Code
  4. 从零开始学网络|搞懂OSI参考模型和TCP/IP分层模型,看这篇文章就够了
  5. 玄姐出品:想和兄弟、集美们聊聊“分布式CAP”中情侣的纠缠故事,真是剪不断 理还乱!...
  6. 【仿59store校园o2o系统 v6.8】夜猫店+校园超市+学生街+微信公众号绑定+校园跑腿插件
  7. android socket编程实例
  8. main方法中args_public static void main(String [] args)– Java main方法
  9. 伺服驱动伺服电机选型究竞有哪些问题要注意??
  10. Excel表格快捷键使用
  11. 怎么设置计算机用户账户和密码,电脑上怎么设置wifi用户名和密码
  12. CSDN版主考核方案
  13. iOS客户端如何测试推送
  14. 架构系列---一套高并发IM通信系统完整设计和实现
  15. Windows Server 2016搭建文件服务器
  16. 【财富空间】华为HR总裁李杰:如何打造一支胜任的项目经理队伍?
  17. 技术干货丨摄像头管理功能架构,EdgeX ONVIF/USB 管理和推理平台
  18. 5G时代,云计算发展的五大新趋势
  19. PCB表面处理工艺之OSP的优缺点?
  20. 基本概念篇(一),强化学习基本要素

热门文章

  1. python垃圾回收机制为什么标记能解决循环引用问题_Python 垃圾回收机制和如何解决循环引用...
  2. dubbo优势_Dubbo 迈出云原生重要一步 应用级服务发现解析
  3. 用java写注册表单_利用HTML表单标签编写一个注册页面
  4. python跟java 效率_Python和Java该如何选择?老男孩Python人工智能
  5. linux 内核 三天吐血,编译安装——吐血经验,内附脚本
  6. java 手机 上传图片_在手机端使用拍照功能上传图片的功能的解决文案
  7. Linux中append函数的用法,linux C代码 open函数参数:O_APPEND问题求助
  8. linux获取tomcat进程,Shell 获取Tomcat进程号
  9. infor wms 项目启动_广汽本田增城工厂No.2L WMS项目正式启动
  10. int函数在Oracle,vb中int是什么意思 ?