「Pudding Monsters」Solution

2024-05-02 09:44
文章标签 solution monsters pudding

本文主要是介绍「Pudding Monsters」Solution,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简述题意

给定一个 n × n n \times n n×n 的棋盘,其中有 n n n 个棋子,每行每列恰好有一个棋子。

对于所有的 1 ≤ k ≤ n 1 \leq k \leq n 1kn,求有多少个 k × k k \times k k×k 的子棋盘中恰好有 k k k 个棋子,输出其总和。

  • n ≤ 3 × 1 0 5 n \le 3 \times 10^5 n3×105

思路

在某个 k × k k \times k k×k 的子矩阵中,显然行是连续的,列也是连续的。并且,每行每列恰好只有一个棋子,即每一行都唯一对应着某一列,这都启发我们把二维平面压缩成一个排列,即令 a [ x ] = y a[x]=y a[x]=y
那么 k × k k \times k k×k 的子矩阵中有 k k k 1 1 1 就等价于 a a a 中某段子序列的值是连续的,原题就转化为经典的 值域连续段个数 问题。

可能有点抽象,举个例子:
a : [ 1 , 5 , 2 , 4 , 3 ] a:[1,5,2,4,3] a:[1,5,2,4,3],满足条件的子序列就有 [ 1 ] , [ 5 ] , [ 2 ] , [ 4 ] , [ 3 ] , [ 4 , 3 ] , [ 2 , 4 , 3 ] , [ 5 , 2 , 4 , 3 ] [ 1 , 5 , 2 , 4 , 3 ] [1],[5],[2],[4],[3],[4,3],[2,4,3],[5,2,4,3][1,5,2,4,3] [1],[5],[2],[4],[3],[4,3],[2,4,3],[5,2,4,3][1,5,2,4,3],如果还觉得抽象可以把上述子序列还原成二维,可以加深理解。

然而,值域连续是很难刻画的,一般从最值入手,即如果某个子序列 [ l , r ] [l,r] [l,r] 值域连续,其一定满足:

max ⁡ { a l , a l + 1 , . . . , a r − 1 , a r } − min ⁡ { a l , a l + 1 , . . . , a r − 1 , a r } = r − l \max\{a_l,a_{l+1},...,a_{r-1},a_r\} - \min\{a_l,a_{l+1},...,a_{r-1},a_r\}=r-l max{al,al+1,...,ar1,ar}min{al,al+1,...,ar1,ar}=rl

还有一个条件是 [ l , r ] [l,r] [l,r] 中每一个数仅出现一次,然而这个条件在此题中是天然满足的。

因此,我们只需要知道有哪些子序列的最大值减去最小值等于序列长度即可,对于序列计数问题,一般都是固定某个端点进行统计,而值域连续段就是通过固定右端点实现的。

不妨令现在的右端点为 r p o s rpos rpos,并用一颗线段树维护左端点,具体地,某个节点 [ l , r ] [l,r] [l,r] 表示的就是对于 ∀ i ∈ [ l , r ] , [ i , r p o s ] \forall i \in[l,r],[i,rpos] i[l,r][i,rpos] m a x − m i n + i − r p o s \mathrm{max} - \mathrm{min} + i - rpos maxmin+irpos 的值,然而,我们是难以统计上述式子的所有取值的,因此引入一个性质:

  • 对于某个子序列 [ l , r ] [l,r] [l,r],一定有 m a x − m i n + l − r ≥ 0 \mathrm{max} - \mathrm{min} + l - r \ge 0 maxmin+lr0

因此,对于当前右端点,由于 [ r p o s , r p o s ] [rpos,rpos] [rpos,rpos] 上述式子的值显然为 0 0 0,所以 r p o s rpos rpos 结尾的所有子序列中上述式子的最小值一定是 0 0 0。因此,我们只需要维护线段树上的最小值以及最小值出现的次数,就是 m a x − m i n + l − r = 0 \mathrm{max} - \mathrm{min} + l - r = 0 maxmin+lr=0 的个数。

考虑如何维护线段树。

  • 对于式子中的 + l +l +l,直接将线段树叶子节点(即左端点)的初值置为 l l l 即可。
  • 对于式子中的 − r -r r,我们每次 r ← r + 1 r \leftarrow r+1 rr+1 时,给全局每一个位置减去 1 1 1 即可。
  • 而子序列最大值,最小值就用单调栈维护。以最大值为例,记单调栈为 s s s,栈顶为 t o p top top,如果 a s t o p ≤ a i a_{s_{top}} \le a_i astopai,那么就说明,对于 j ∈ [ s t o p − 1 + 1 , s t o p ] , [ j , i ] j \in [s_{top-1}+1,s_{top}],[j,i] j[stop1+1,stop],[j,i] 这些子序列,其的最大值由 a s t o p a_{s_{top}} astop 变为了 a i a_i ai,那么我们给区间 [ s t o p − 1 + 1 , s t o p ] [s_{top-1}+1,s_{top}] [stop1+1,stop] 加上一个 a i − a s t o p a_i-a_{s_{top}} aiastop 即可,然后 t o p ← t o p − 1 top \leftarrow top-1 toptop1 继续维护单调栈即可。最小值同理,不过区间加变为区间减了。

代码

上述做法就是值域连续段的经典解法,算是一个 trick \text{trick} trick 吧 (((

#include<bits/stdc++.h>
#define int long long
#define pii pair<int , int>
using namespace std;
const int MAXN = 3e5 + 5;
namespace Segment{struct tree{int l , r , add , Min , cnt;}tree[MAXN << 3];void pushup(int p) {tree[p].Min = min(tree[p << 1].Min , tree[p << 1 | 1].Min) , tree[p].cnt = 0;if (tree[p << 1].Min == tree[p].Min) tree[p].cnt += tree[p << 1].cnt;if (tree[p << 1 | 1].Min == tree[p].Min) tree[p].cnt += tree[p << 1 | 1].cnt;}void pushdown(int p) {tree[p << 1].Min += tree[p].add , tree[p << 1 | 1].Min += tree[p].add;tree[p << 1].add += tree[p].add , tree[p << 1 | 1].add += tree[p].add;tree[p].add = 0;}void build(int p , int l , int r) {tree[p].l = l , tree[p].r = r , tree[p].add = 0;if (l == r){tree[p].Min = l , tree[p].cnt = 1;return;}int mid = l + r >> 1;build(p << 1 , l , mid) , build(p << 1 | 1 , mid + 1 , r);pushup(p);}void update(int p , int l , int r , int v) {if (tree[p].l >= l && tree[p].r <= r) {tree[p].add += v , tree[p].Min += v;return;}pushdown(p);int mid = tree[p].l + tree[p].r >> 1;if (l <= mid) update(p << 1 , l , r , v);if (r > mid) update(p << 1 | 1 , l , r , v);pushup(p);}pii query(int p , int l , int r) {if (tree[p].l >= l && tree[p].r <= r) return make_pair(tree[p].Min , tree[p].cnt);pushdown(p);int mid = tree[p].l + tree[p].r >> 1;pii tmp1 , tmp2;tmp1.first = tmp2.first = 1e9;if (l <= mid) tmp1 = query(p << 1 , l , r);if (r > mid) tmp2 = query(p << 1 | 1 , l , r);if (tmp1.first < tmp2.first) return tmp1;if (tmp1.first > tmp2.first) return tmp2;return make_pair(tmp1.first , tmp1.second + tmp2.second);}
}
using namespace Segment;
int n , a[MAXN] , s1[MAXN] , top1 , s2[MAXN] , top2 , ans;
signed main() {ios::sync_with_stdio(false);cin.tie(nullptr) , cout.tie(nullptr);cin >> n;for (int i = 1 , x , y ; i <= n ; i ++) {cin >> x >> y;a[x] = y;}build(1 , 1 , n);for (int i = 1 ; i <= n ; i ++) {update(1 , 1 , n , -1);while (top1 && a[s1[top1]] <= a[i]) update(1 , s1[top1 - 1] + 1 , s1[top1] , a[i] - a[s1[top1]]) , top1 --;s1[++ top1] = i;while (top2 && a[s2[top2]] >= a[i]) update(1 , s2[top2 - 1] + 1 , s2[top2] , a[s2[top2]] - a[i]) , top2 --;s2[++ top2] = i;ans += query(1 , 1 , i).second;}cout << ans;return 0;
}

这篇关于「Pudding Monsters」Solution的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/953964

相关文章

AtCoder Beginner Contest 370 Solution

A void solve() {int a, b;qr(a, b);if(a + b != 1) cout << "Invalid\n";else Yes(a);} B 模拟 void solve() {qr(n);int x = 1;FOR(i, n) FOR(j, i) qr(a[i][j]);FOR(i, n) x = x >= i ? a[x][i]: a[i][x];pr2(

error on “nvm list available“, find the final solution by the Second error

error one Could not retrieve https://nodejs.org/dist/index.json. Get “https://nodejs.org/dist/index.json”: dial tcp 104.20.23.46:443: i/o timeout error two Error retrieving “http://npm.taobao.org/m

Deep in MTK Turnkey Solution Logging Tools

一个完整的日志系统除了Log保存机制以外,还要有Log查看机制。不管是Kernel Log还是Android Log都会将Log打印到buffer,那么Log工具则会将Buffer里面的Log拿出来做相应的处理,或者打印到终端,或者对Log做解析以及过滤等等。而Kernel Log除了打印到buffer以外还会打印到Console,那么从console获取Log也是一种常见的方式。 那到底都

Python typeError: a bytes-like object is required, not ‘str’ Solution

目录 一、需求 二、报错 三、解决方法 一、需求 调接口解析其中 dis 字段。 二、报错 Python Typeerror a bytes-like object is required not ‘str’ 这句话的意思是“类型错误:需要类似字节的对象,而不是字符串”。 三、解决方法 在需要解析的字段前 加上 b 原代码: if 'dis' in response

Error occurred in deployment step 'Retract Solution': Invalid object name 'AllWebs'

Check the error message on Monitoring-->Review Project and solutions, and try running SharePoint 2010 Products Configuration Wizard.

「Destiny」Solution

简述题意 给定 n n n 个元素, q q q 次询问。 每次给出三个参数 l , r , k l, r, k l,r,k,询问区间 [ l , r ] [l, r] [l,r] 内是否存在出现次数严格大于 r − l + 1 k \frac{r - l + 1} {k} kr−l+1​ 的数。如果有,输出最小的那个数,否则输出 − 1 -1 −1。 1 ≤ n , q ≤ 3

XML Problem Design Solution

版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出版、作者信息和本声明。否则将追究法律责任。 http://blog.csdn.net/topmvp - topmvp *Offering a unique approach to learning XML, this book walks readers through the process of building a co

netty-time-Second Solution

TimeServer、TimeServerHandler同上篇文章。 package org.q.netty.time2;import java.net.InetSocketAddress;import java.util.concurrent.Executors;import org.jboss.netty.bootstrap.ClientBootstrap;import org.jb

「Positions in Permutations」Solution

简述题意 给定 n , m n,m n,m,对于一个长度为 n n n 的排列 p p p,有函数: F ( p ) = ∑ i = 1 n [ ∣ p i − i ∣ = 1 ] F(p)=\sum_{i=1}^{n}[\left|p_i-i\right|=1 ] F(p)=i=1∑n​[∣pi​−i∣=1]求有多少个排列满足 F ( p ) = m F(p) = m F(p)=m,答

gradle bug solution

集成一个第三方sdk,遇到了如下问题 Error:Execution failed for task ':lumbar:processDebugManifest'.> Manifest merger failed with multiple errors, see logs 搞了几天把网上能找的中文英文的翻了几遍,梳理了几遍,始终解决不了,直到有一天,点开了一个知乎的帖子,没错,就这这个问题