P5665 [CSP-S2019] 划分

P5665 [CSP-S2019] 划分

难度:省选/NOI-

考点:单调队列、贪心、前缀和

题意:

没有题目大意,本题题目描述较长,认真阅读每一个信息。

​ 这个题的样例有 n n n 组数据,数据从 1 ∼ n 1 \sim n 1n 编号, i i i 号数据的规模为 a i a_i ai

​ 小明对该题设计出了一个暴力程序,对于一组规模为 u u u 的数据,该程序的运行时间 u 2 u^2 u2。然而这个程序运行完一组规模为 u u u 的数据之后,它将在任何一组规模小于 u u u 的数据上运行错误。样例中的 a i a_i ai 不一定递增,但小明又想在不修改程序的情况下正确运行样例,于是小明决定使用一种非常原始的解决方案:将所有数据划分成若干个数据段,段内数据编号连续,接着将同一段内的数据合并成新数据,其规模等于段内原数据的规模之和,小明将让新数据的规模能够递增。

​ 也就是说,小明需要找到一些分界点 1 ≤ k 1 < k 2 < ⋯ < k p < n 1 \leq k_1 \lt k_2 \lt \cdots \lt k_p \lt n 1k1<k2<<kp<n,使得

∑ i = 1 k 1 a i ≤ ∑ i = k 1 + 1 k 2 a i ≤ ⋯ ≤ ∑ i = k p + 1 n a i \sum_{i=1}^{k_1} a_i \leq \sum_{i=k_1+1}^{k_2} a_i \leq \cdots \leq \sum_{i=k_p+1}^{n} a_i i=1k1aii=k1+1k2aii=kp+1nai
​ 注意 p p p 可以为 0 0 0 且此时 k 0 = 0 k_0 = 0 k0=0,也就是小明可以将所有数据合并在一起运行。

​ 小明希望他的程序在正确运行样例情况下,运行时间也能尽量小,也就是最小化

( ∑ i = 1 k 1 a i ) 2 + ( ∑ i = k 1 + 1 k 2 a i ) 2 + ⋯ + ( ∑ i = k p + 1 n a i ) 2 (\sum_{i=1}^{k_1} a_i)^2 + (\sum_{i=k_1+1}^{k_2} a_i)^2 + \cdots + (\sum_{i=k_p+1}^{n} a_i)^2 (i=1k1ai)2+(i=k1+1k2ai)2++(i=kp+1nai)2
​ 小明觉得这个问题非常有趣,并向你请教:给定 n n n a i a_i ai,请你求出最优划分方案下,小明的程序的最小运行时间。

输入格式

由于本题的数据范围较大,部分测试点的 a i a_i ai 将在程序内生成。

第一行两个整数 n , t y p e n, type n,type n n n 的意义见题目描述, t y p e type type 表示输入方式。

  1. t y p e = 0 type = 0 type=0,则该测试点的 a i a_i ai 直接给出。输入文件接下来:第二行 n n n 个以空格分隔的整数 a i a_i ai,表示每组数据的规模。
  2. t y p e = 1 type = 1 type=1,则该测试点的 a i a_i ai特殊生成,生成方式见后文。输入文件接下来:第二行六个以空格分隔的整数 x , y , z , b 1 , b 2 , m x, y, z, b_1, b_2, m x,y,z,b1,b2,m。接下来 m m m 行中,第 i ( 1 ≤ i ≤ m ) i (1 \leq i \leq m) i(1im) 行包含三个以空格分隔的正整数 p i , l i , r i p_i, l_i, r_i pi,li,ri

对于 t y p e = 1 type = 1 type=1 的 23~25 号测试点, a i a_i ai 的生成方式如下:

给定整数 x , y , z , b 1 , b 2 , m x, y, z, b_1, b_2, m x,y,z,b1,b2,m,以及 m m m 个三元组 ( p i , l i , r i ) (p_i, l_i, r_i) (pi,li,ri)

保证 n ≥ 2 n \geq 2 n2。若 n > 2 n \gt 2 n>2,则 ∀ 3 ≤ i ≤ n , b i = ( x × b i − 1 + y × b i − 2 + z ) m o d    2 30 \forall 3 \leq i \leq n, b_i = (x \times b_{i−1} + y \times b_{i−2} + z) \mod 2^{30} ∀3in,bi=(x×bi1+y×bi2+z)mod230

保证 1 ≤ p i ≤ n , p m = n 1 \leq p_i \leq n, p_m = n 1pin,pm=n。令 p 0 = 0 p_0 = 0 p0=0,则 p i p_i pi 还满足 ∀ 0 ≤ i < m \forall 0 \leq i \lt m ∀0i<m p i < p i + 1 p_i \lt p_{i+1} pi<pi+1

对于所有 1 ≤ j ≤ m 1 \leq j \leq m 1jm,若下标值 i ( 1 ≤ i ≤ n ) i (1 \leq i \leq n) i(1in)满足 p j − 1 < i ≤ p j p_{j−1} \lt i \leq p_j pj1<ipj,则有

a i = ( b i m o d    ( r j − l j + 1 ) ) + l j a_i = \left(b_i \mod \left( r_j − l_j + 1 \right) \right) + l_j ai=(bimod(rjlj+1))+lj

上述数据生成方式仅是为了减少输入量大小,标准算法不依赖于该生成方式。

分析

一会儿再来看输入输出的方式怎么根据题目的意思去构造数据,先分析分析本题怎么做。

​ 本题前面的 16 16 16 个测试点 n ≤ 4 × 1 0 7 n \le 4 \times 10^7 n4×107,可以使用 DP 的 做法来解决,但后面 17 ∼ 25 17 \sim 25 1725 个测试点需要贪心的去思考。

​ 如何使运行时间最小呢?也就是下面这一坨。
( ∑ i = 1 k 1 a i ) 2 + ( ∑ i = k 1 + 1 k 2 a i ) 2 + ⋯ + ( ∑ i = k p + 1 n a i ) 2 (\sum_{i=1}^{k_1} a_i)^2 + (\sum_{i=k_1+1}^{k_2} a_i)^2 + \cdots + (\sum_{i=k_p+1}^{n} a_i)^2 (i=1k1ai)2+(i=k1+1k2ai)2++(i=kp+1nai)2

​ 要从 均值不等式 的角度上进行思考,举个例子:给定一个数字 100 100 100,如果拆分成 2 2 2 50 50 50,那么计算贡献时就是 5 0 2 + 5 0 2 = 5000 50^2 + 50^2 = 5000 502+502=5000,但是我们拆分成 100 100 100 1 1 1,那么计算贡献就是 1 + 1 + . . . + 1 = 100 1+1+...+1=100 1+1+...+1=100,受此启发:如果拆分的段数越多越好,而且段与段之间差值越小越好。

​ 假设我们有这样一段, S 1 ≤ S 2 ≤ . . . ≤ S m S_1 \le S_2 \le ... \le S_m S1S2...Sm ,大胆的猜测一下:肯定希望最后一项即 S m S_m Sm 越小越好,即最大的和 S m S_m Sm 越小,那么前面比它小的也会小,也意味着每一段之间的方差值比较小,同时段数也会很多,因为总和一定的情况下,如果最大的和很小,那么分出来的段数也会多。

​ 猜想:要让最后一段的和越小越好。

如果考场上没有往均值不等式去猜出来怎么办?只能拿部分分,没有别的办法。

​ 根据猜想,尝试构造一个方案是的最后段的和越小越好。

在这里插入图片描述

s [ i ] s[i] s[i]:表示前 i i i 个数的和,假设最后一段的右端点是 i i i,前一段右端点为 j j j,最后一段区间就是 [ j + 1 , i ] [j+1,i] [j+1,i],最后一段数字的和就可以用 S i − S j S_i - S_j SiSj 来表示。贪心:我们希望 j j j 越大越好,代表越靠近 i i i 。我们可以尝试枚举符合的 j j j。怎么判断是否 j j j 是否满足条件呢?

j j j 满足条件,当且仅当:存在一个方案,使得 s [ i ] − s [ j ] ≥ s[i] - s[j] \ge s[i]s[j] j j j 结尾这一段的总和。

在这里插入图片描述

​ 假设上一段是 S k + 1 S_k+1 Sk+1 为开头, S j S_j Sj 为结尾的区间 [ S k , S j ] [S_k,S_j] [Sk,Sj],满足 S i − S j ≥ S j − S k S_i - S_j \ge S_j - S_k SiSjSjSk i i i 是希望找到以 i i i 为结尾最短的一段。

​ 这种定义其它对每一段都合适,假设已经求出来以 j j j 为结尾最后一段中最短的方案,假设是 k + 1 k+1 k+1 开头是所有方案里面最短的。

​ 假设 g [ j ] g[j] g[j] 表示所有以 j j j 为结尾的方案数,最后一段最短的方案,对应的倒数第二段的结尾。

​ 即: S i − S j ≥ S j − S g j S_i - S_j \ge S_j - S_{g_j} SiSjSjSgj

​ 最后一段的区间就可以表示为 [ g j + 1 , g j + 2... g [ j ] ] [g_{j}+1,g_{j}+2...g[j]] [gj+1,gj+2...g[j]] ,判断是否存在以 j j j 结尾的方案, j j j 如果存在,则存在一个方案使得 S i − S j ≥ S j − S g j S_i - S_j \ge S_j -S_{g_{j}} SiSjSjSgj [ j + 1 , i ] [j+1,i] [j+1,i] 的区间和大于等于 [ g j + 1 , j ] [g_{j}+1,j] [gj+1,j] 的区间和,所有方案当中最后一段间隔最小的。判断 j j j 是否存在的话,就可以直接判断是否存在 S i − S j ≥ S j − S g j S_i-S_j \ge S_j - S_{g_j} SiSjSjSgj 就可以了。

​ 常用判断是否存在解的话,常用的方法就是在某个集合当中是否存在至少一个方案,如果存在则解一定存在,例如集合中求最小的一个方案,如果存在至少一个方案,那么这个方案就是解。上述的式子来判断是否存在 j j j 就可以判断是否满足有至少一种方案满足 S i − S j ≥ S j − S g j S_i - S_j \ge S_j - S_{g_j} SiSjSjSgj,如果满足则 j j j 就必定存在。

​ 这种贪心的 g j g_j gj 其实是可以递推出来的,从 0 ∼ ( i − 1 ) 0 \sim (i-1) 0(i1) 中去枚举 j j j,在所有满足上述式子中取一个最大就为答案,也就是 g i g_i gi 的取值,所有符合的条件中满足 g i g_i gi j j j 中最大的一个。

​ 有了这个贪心的思路之后,那这个贪心是否正确的呢?接下来就是关于贪心的证明。

这个贪心的证明,还是相对来说很抽象,需要一定的跳跃性思维。

​ 本题的证明也不是常见证明贪心的思路,通过调整然后使得答案越来越好。而是直接证!

​ 把贪心的思路先绘制出来,每一段的和用编号 a 1 ∼ a n a_1 \sim a_n a1an 来表示,共有 n n n 段(倒着来编号,最后会发现比较好证,如下图)

在这里插入图片描述

​ 注意,上图绘制的是通过刚刚的贪心思路得到的序列 A A A,每一段都是唯一确定的,每一段都是最大的间隔最短的。

​ 接下来是任意其它的思路的方案序列 B B B,来证明 A 将会是更优。其中每一段的和用 b 1 ∼ b m b_1 \sim b_m b1bm 来表示,共有 m m m 段。

在这里插入图片描述

​ 小的思考细节, A A A B B B 的序列划分个数 n , m n,m n,m 可以不一样,因为可以通过合并调整的方式来使得它们一样。举个例子,我们可以设 n = 5 , m = 4 n=5,m=4 n=5,m=4 有形如下图的一个序列,我们可以通过让 b 5 = 0 b_5=0 b5=0,来凑齐相等的段数且不会影响结果,因为 0 2 = 0 0^2=0 02=0
在这里插入图片描述

​ 这里需要证明些什么呢?假设 B B B 序列的代价(即每一项 b i b_i bi 的平方和)是 f ( B ) f(B) f(B) A A A 序列的代价是 f ( A ) f(A) f(A),证明 f ( B ) > f ( A ) f(B) > f(A) f(B)>f(A)

​ 如何可以证明出所有其它方案 f ( B 1 ) , f ( B 2 ) . . . f(B_1), f(B_2) ... f(B1),f(B2)... 的代价都严格大于贪心方案 f ( A ) f(A) f(A),那么就贪心的正确性就有了。

​ 把表达式展开就是求: ∑ i = 1 m b i 2 > ∑ i = 1 n a i 2 \sum\limits_{i=1}^{m} b_i^2 \gt \sum\limits_{i=1}^{n}a_i^2 i=1mbi2>i=1nai2,要证明就要挖掘一些性质出来。

在这里插入图片描述

  1. 根据题目的要求,每一段区间平方和要满足前一项严格小于后一段区间平方和,即 a 1 ≥ a 2 ≥ . . . ≥ a n ≥ 0 , a i ∈ N a_1 \ge a_2 \ge ... \ge a_n \ge 0, a_i \in \mathbb{N} a1a2...an0,aiN

  2. b b b 同上面一样要满足 b 1 ≥ b 2 ≥ . . . ≥ b m ≥ 0 , b i ∈ N b_1 \ge b_2 \ge ... \ge b_m \ge 0,b_i \in \mathbb{N} b1b2...bm0,biN

  3. 不同方案,但是序列总和都是一样,即: ∑ i = 1 n a i = ∑ i = 1 m b i \sum\limits_{i=1}^{n} a_i = \sum\limits_{i=1}^{m} b_i i=1nai=i=1mbi

  4. 贪心方案是每一段都是选择间隔最短最靠右的,那么 a 1 a_1 a1 (已经是最靠后的点) 为讨论点,那么 b 1 b_1 b1 只会在 a 1 a_1 a1 的位置或者前面( 形如下图 1 1 1,确定了 b 1 b_1 b1 这个点选点会在 a 1 a_1 a1 的前面),即 a 1 ≤ b 1 a_1 \le b_1 a1b1 a 1 a_1 a1 最小则最靠右,再分析下一个点 b 2 b_2 b2

    1 1 1
    在这里插入图片描述

    b 2 b_2 b2 这个点会在 a 2 a_2 a2 的前面吗( ≤ a 2 \le a_2 a2 )?(如下图 2 ),看是否产生矛盾就行,分析一下,假设 b 2 b_2 b2 这个点落在了 a 2 a_2 a2 之前,同时以 b 2 b_2 b2 为结尾的后面一段 b 3 b_3 b3,就有 b 2 ≤ a 2 b_2 \le a_2 b2a2,其中 a 2 a_2 a2 结尾被改变了,与贪心方案的描述对不上,因为 a 2 a_2 a2 是所有以 a 1 a_1 a1 为结尾方案中间隔最小且最早的一段,如果 a 2 a_2 a2 不是间隔最小且最早的一段则与描述出现矛盾 (如下图 3),故 b 2 b_2 b2 只会落位在 a 2 a_2 a2 的前面。

    2 2 2

在这里插入图片描述

图 3:

在这里插入图片描述

b 3 b_3 b3 的落位点是同上一样,只会在 a 3 a_3 a3 的左边,否则会与贪心方案中最早间隔最小一段描述不符矛盾(如下图 4)。

图 4:

在这里插入图片描述

性质: ∃   1 ≤ k ≤ n , a 1 + a 2 + . . . + a k ≤ b 1 + b 2 + . . . + b k \exists \space 1 \le k \le n, a_1 + a_2 + ... + a_k \le b_1 + b_2 + ... + b_k  1kn,a1+a2+...+akb1+b2+...+bk

可以完全抛开原来问题,完全变成一个数学问题了。我们要证明所有「其它」序列 b [ i ] b[i] b[i] 都满足 a 1 + a 2 + . . . + a n ≤ b 1 + b 2 + . . . + b m a_1 + a_2 + ... + a_n \le b_1 + b_2 + ... + b_m a1+a2+...+anb1+b2+...+bm

本题其实用不上 4 个性质,只需要 1、3、4 就可以了。

  1. a 1 ≥ a 2 ≥ . . . ≥ a n ≥ 0 , a i ∈ N a_1 \ge a_2 \ge ... \ge a_n \ge 0, a_i \in \mathbb{N} a1a2...an0,aiN
  2. ∑ i = 1 n a i = ∑ i = 1 m b i \sum\limits_{i=1}^{n} a_i = \sum\limits_{i=1}^{m} b_i i=1nai=i=1mbi
  3. ∃   1 ≤ k ≤ n , a 1 + a 2 + . . . + a k ≤ b 1 + b 2 + . . . + b k \exists \space 1 \le k \le n, a_1 + a_2 + ... + a_k \le b_1 + b_2 + ... + b_k  1kn,a1+a2+...+akb1+b2+...+bk

为什么第 2 个性质用不上呢?现在来证明一下,也好证明:

在所有其它 B B B 方案中,我们可以通过 逐步调整 B B B 使得 B B B 不断的靠近 A A A,同时可以保证平方和严格变小。

  • B ⟶ B 1 ⟶ B 2 ⟶ . . . ⟶ A B \longrightarrow B_1 \longrightarrow B_2\longrightarrow ... \longrightarrow A BB1B2...A
  • B > B 1 ≥ B 2 > . . . > A B \gt B_1 \ge B_2 \gt ... \gt A B>B1B2>...>A
  • A ≤ B A \le B AB

本题事先说明,已经完全脱离了原来题目的意思,用数学的方案来证明了贪心的思路是正确的。

什么意思呢?如上我们使用了逐步调整的方式使得 B B B 不断靠近 A A A,来证明出 A ≤ B A \le B AB,而本题完全是用数学的角度去证明的,但是 B 和 A 分别还是代表着 其它方案 和 贪心方案。但是中间的 B 1 B_1 B1 B 2 B_2 B2 不一定对应着原来问题的某种方案。但这并不影响我们证明。 我们只需要证明 A < B A \lt B A<B 中间产生的任何状态都与原问题没有任何关系。

证明所有「其它」序列 b [ i ] b[i] b[i] 都满足 a 1 + a 2 + . . . + a n ≤ b 1 + b 2 + . . . + b m a_1 + a_2 + ... + a_n \le b_1 + b_2 + ... + b_m a1+a2+...+anb1+b2+...+bm

接下来问题就跟原问题没有太大关联了,只需要证明不等式成立即可。

​ 证明之前先要知道序列之间的距离 D D D,其中 D ( A , B ) = ∣ a 1 − b 2 ∣ + ∣ a 2 − b 2 ∣ + . . . + ∣ a n − b n ∣ D(A,B) = |a_1-b_2| + |a_2 - b_2| + ... + |a_n - b_n| D(A,B)=a1b2+a2b2+...+anbn 的距离,当距离等于 0 0 0 的时候,说明每一项都是相等的。

​ 通过一种构造 (调整合并) 的方案,使得 A A A B B B 的距离逐步变小,初始的时候,每一项都是一个有限值,每一步方案都让 B 严格变小,经过有限步就必然可以让 B B B 变成 A A A。可以证明出每次变小,平方和都会变小,所以就可以证明出 ∑ i = 1 n B 1 < ∑ i = 1 n B \sum\limits_{i=1}^{n} B1 \lt \sum\limits_{i=1}^{n} B i=1nB1<i=1nB

​ 怎么构造这种方案呢?怎么将 B > B 1 ≥ B 2 > . . . > A B \gt B_1 \ge B_2 \gt ... \gt A B>B1B2>...>A

​ 假设这两个序列 ( A , B ) (A,B) (A,B) 1 ∼ x − 1 1 \sim x-1 1x1 位置上都是相等的,而到达 x x x 的位置开始不相等(如下),切每一项的和都满足 a i a_i ai 小于等于 b i b_i bi,满足 ∑ i = 1 x a i ≤ ∑ i = 1 x b i \sum\limits_{i=1}^{x}a_i \le \sum\limits_{i=1}^{x}b_i i=1xaii=1xbi ,即第 x x x 个位置只能 a a a 小于 b b b,不可能大于,否则 a a a 的前缀和就会大于 b b b 的前缀和不符合贪心方案的设定。

a 1 , a 2 , . . . a x . . . a y . . . a n a_1,a_2,...a_x...a_y...a_n a1,a2,...ax...ay...an

b 1 , b 2 , . . . b x . . . b y . . . b n b_1,b_2,...b_x...b_y...b_n b1,b2,...bx...by...bn

​ 那么 a x < b x a_x \lt b_x ax<bx,且根据上述的性质 2 2 2 a 、 b a、b ab 序列的总和相等,那必然在 a a a 序列中有一个数 a y > b y a_y > b_y ay>by 。又由于性质 1 1 1 可知, a a a 序列是递减的,那么就有 b x > a x ≥ a x + 1 ≥ a x + 1 ≥ . . . ≥ a y > b y b_x \gt a_x \ge a_{x+1} \ge a_{x+1} \ge ... \ge a_y \gt b_y bx>axax+1ax+1...ay>by 从这个式子中也可以观察得到一些性质,和在一定的情况下,两个数的差越小平方和也会越小。总和就是 b x − b y b_x - b_y bxby,我们尝试将 b x − 1 b_x-1 bx1 b y + 1 b_y+1 by+1,那么将会满足 b x − 1 ≥ a x ≥ a x + 1 ≥ . . . ≥ a y ≥ b y + 1 b_x-1 \ge a_x \ge a_{x+1} \ge ... \ge a_y \ge b_y+1 bx1axax+1...ayby+1

​ 仍然满足 b x − 1 ≥ b y + 1 b_x-1 \ge b_y+1 bx1by+1,相当于 b b b 序列中两个数,大的数减去 1和小的数加上 1 之后,还是满足大于等于的情况。

​ 那么怎么证明这个不等式成立的呢?
b x 2 + b y 2 − ( b x − 1 ) 2 − ( b y + 1 ) 2 = 2 b x − 1 − 2 b y − 1 = 2 ( b x − b y ) − 2 b_x^2 + b_y^2 - (b_x - 1) ^2 - (b_y+1)^2 \newline = 2b_x - 1 - 2b_y - 1 \newline = 2(b_x-b_y) - 2 bx2+by2(bx1)2(by+1)2=2bx12by1=2(bxby)2
由于要满足 b x − 1 ≥ b y + 1 b_x-1 \ge b_y +1 bx1by+1,移项后 b x − b y ≥ 2 b_x - b_y \ge 2 bxby2,结合上面的不等式可以发现, 2 ( b x − b y ) − 2 ≥ 2 2(b_x-b_y)-2 \ge 2 2(bxby)22

​ 可以发现在 b b b 序列当中,要取出「第一个」满足 a y > b y a_y > b_y ay>by y y y,满足其中一个数减 b x − 1 b_x-1 bx1,另外一个数加 b y + 1 b_y+1 by+1,平方和每次至少会减去 2 2 2。每次将比 a a a 序列大的数 (上面分析中 a x a_x ax ) 减去 1 1 1,比 a a a 序列小的数 (上面分析中 a y a_y ay ) 加上 1 1 1,所以我们相当于对绝对值的差值 ∣ a i − b i ∣ |a_i-b_i | aibi 会变小。

​ 故我们可以发现,每个序列的取出「第一个」满足 a y > b y a_y \gt b_y ay>by y y y,让序列的差值每次至少减去 2 2 2,又因为 n n n 是有限值,所以可以通过若干次操作就可以使得 $D(A,B) = |a_1-b_2| + |a_2 - b_2| + … + |a_n - b_n| $ 值为 0 0 0,即 A = B A=B A=B 序列。而且 b b b 序列每次操作至少会让平方和至少减去 2 2 2,所以每次操作都会让平方进行减少,每一个跟 a a a 不一样的 b b b 都可以一系列有限次的操作都会变成 A A A,每一步变化都会严格变小,所以可以发现任何一个 B > A B \gt A B>A

​ 证明完毕,贪心方案:最后段的和越小越好,正确。

​ 就会满足 S i − S j ≥ S j − S g j S_i - S_j \ge S_j - S_{g_j} SiSjSjSgj ,整理后 S i ≥ 2 S j − S g j S_i \ge 2 S_j - S_{g_j} Si2SjSgj ,因为右边只关乎 j j j 的可以定义为 h j h_j hj

​ 相当于在 i i i 点的左边找到第一个满足 S i ≥ h j S_i \ge h_j Sihj 的点 j j j

在这里插入图片描述

​ 上述的式子,要求满足的 j j j 点,可以用 单调队列 来求,为什么呢?

​ (如下图)如果前面的 j j j 当中存在 h k ≤ h j h_k \le h_j hkhj 的点 k k k,那么就可以将 j j j 点替换成 k k k 点,因为我们要找的是最靠右边的 j j j 。那么相当于如果发现右边存在比他小的数字就进行替换 / 删除,那么整个答案序列会是一个单调递增的序列,故可以用单调队列来维护。

在这里插入图片描述

在这里插入图片描述

​ 那么我们可以发现找到满足最后一个 ≤ S i \le S_i Si 的数 h j h_j hj。可以不用二分,直接用单调队列的单调性来维护,从对头开始删除,只要满足 ≤ S i \le S_i Si 就一直删除,直到最后一个满足 ≤ S i \le S_i Si 的数 h j h_j hj,每个元素最多只会进队和出队一次,均摊下来的时间复杂度是 O ( 1 ) O(1) O(1) 的,总的时间复杂度就是 O ( n ) O(n) O(n)

参考代码

#include <bits/stdc++.h>
#define ll long long
#define BL __int128

const int N = 40000010, MOD = 1 << 30;
int n, type;
int w[N], q[N], g[N]; // 单点贡献 w[], 单调队列 q[], 记录以 i 为结尾最后一个g[j]
ll s[N];              // 前缀和数组

ll get(int k)
{
    return 2 * s[k] - s[g[k]]; // 2s[j] - s[g[j]]
}

void print(BL res)
{
    // 常见的就是 string 抠出来每一位拼接上去
    std::string str;
    while (res)
    {
        str += std::to_string((int)(res % 10));
        res /= 10;
    }
    std::reverse(str.begin(), str.end());
    // std::cout << s << "\n";
    puts(str.c_str());
}

int main()
{
    std::ios::sync_with_stdio(false), std::cin.tie(nullptr);
    // 计算空间的技巧
    // int sz = sizeof w + sizeof q + sizeof g + sizeof s;
    // printf("%.2lf \n", sz / 1024.0 / 1024);

    std::cin >> n >> type; // 处理输入数据
    if (type == 0)
    {
        for (int i = 1; i <= n; i++)
            std::cin >> w[i];
    }
    else
    {
        int x, y, z, b1, b2, m, p0 = 0;
        std::cin >> x >> y >> z >> b1 >> b2 >> m; // 按照题意模拟计算输入数据
        while (m--)
        {
            int p, l, r;
            std::cin >> p >> l >> r;
            for (int i = p0 + 1; i <= p; i++)
            {
                w[i] = b1 % (r - l + 1) + l;
                int b3 = (x * (ll)b2 + y * (ll)b1 + z) % MOD;
                b1 = b2, b2 = b3;
            }
            p0 = p;
        }
    }

    // 计算前缀和
    for (int i = 1; i <= n; i++)
        s[i] = s[i - 1] + w[i];

    int hh = 0, tt = 0; // 如果区间都合并成 1 个,可以取 0 ,所以单调队列里头尾指针指向 0 代表队列里面已经存在一个元素 0 。
    for (int i = 1; i <= n; i++)
    {
        while (hh <= tt && s[i] >= get(q[hh])) // get() 就是求出 h = 2*s[j]-s[gj]
            hh++;
        hh--; // 最后一个满足 g[j] <= s[i] 的位置
        g[i] = q[hh];
        while (hh <= tt && get(i) <= get(q[tt]))
            tt--;
        q[++tt] = i;
    }

    // 从后往前倒推出每一个区间
    BL res = 0;
    for (int i = n; i; i = g[i])
    {
        BL sum = s[i] - s[g[i]];
        res += sum * sum;
    }
    // std::cout << res << "\n";
    // __int128需要手动输出
    print(res);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/910955.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ThreadX在STM32上的移植:F1,F4通用启动文件tx_initialize_low_level.s

在嵌入式系统开发中&#xff0c;实时操作系统&#xff08;RTOS&#xff09;的选择对于系统性能和稳定性至关重要。ThreadX是一种广泛使用的RTOS&#xff0c;它以其小巧、快速和可靠而闻名。在本文中&#xff0c;我们将探讨如何将ThreadX移植到STM32微控制器上&#xff0c;特别是…

RTT 内核基础学习

RT-Thread 内核介绍 内核是操作系统的核心&#xff0c;负责管理系统的线程、线程间通信、系统时钟、中断以及内存等。 内核位于硬件层之上&#xff0c;内核部分包括内核库、实时内核实现。 内核库是为了保证内核能够独立运行的一套小型的类似C库的函数实现子集。 这部分根据编…

qt QPixmapCache详解

1、概述 QPixmapCache是Qt框架中提供的一个功能强大的图像缓存管理工具类。它允许开发者在全局范围内缓存QPixmap对象&#xff0c;从而有效减少图像的重复加载&#xff0c;提高图像加载和显示的效率。这对于需要频繁加载和显示图像的用户界面应用来说尤为重要&#xff0c;能够…

纯css制作声波扩散动画、js+css3波纹催眠动画特效、【css3动画】圆波扩散效果、雷达光波效果完整代码

一、纯css制作声波扩散动画 参考文章&#xff1a;纯css制作声波扩散动画 播放效果通过音频状态来控制 效果如下 完整代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>波纹动画特效…

CocosCreator 构建透明背景应用(最新版!!!)

文章目录 透明原理补充设置截图以及代码step1: electron-js mian.jsstep2:ENABLE_TRANSPARENT_CANVASstep3:SOLID_COLOR Transparentstep:4 Build Web phonestep5:package electron-js & change body background-color 效果图补充 透明原理 使用Cocos creator 做桌面应用开…

在数据抓取的时候,短效IP比长效IP有哪些优势?

在数据抓取领域&#xff0c;代理IP的选择对于任务的成功率和效率至关重要。短效IP和长效IP各有其特点和适用场景&#xff0c;但在数据抓取过程中&#xff0c;短效IP因其独特的优势而受到青睐。本文将和大家一起探讨短效IP在数据抓取中相比长效IP的优势。 短效IP的定义与特点 …

FTP文件传输操作步骤

FTP文件传输操作步骤 步骤一&#xff1a;运行FTPServer.exe程序 步骤二、设置用户名和密码密码 步骤三、设置共享文件夹 步骤五、点击启动 步骤六、查看电脑ip(FTP server端) 步骤七、连接FTP 此电脑&#xff0c;地址栏输入&#xff1a;ftp://192.168.1.100 回车即可&…

【react使用AES对称加密的实现】

react使用AES对称加密的实现 前言使用CryptoJS库密钥存放加密方法解密方法结语 前言 项目中要求敏感信息怕被抓包泄密必须进行加密传输处理&#xff0c;普通的md5加密虽然能解决传输问题&#xff0c;但是项目中有权限的用户是需要查看数据进行查询的&#xff0c;所以就不能直接…

【网络原理】关于HTTP状态码以及请求的构造的哪些事

前言 &#x1f31f;&#x1f31f;本期讲解关于HTTP协议的重要的机制~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不…

苹果发布iOS 18.2首个公测版:Siri接入ChatGPT、iPhone 16拍照按钮有用了

今天凌晨&#xff0c;苹果正式发布了iOS 18.2首个公测版&#xff0c;将更多AI功能大批量推送给用户。其中最重要的就是Siri接入ChatGPT了&#xff0c;用户不必创建账户就可以免费使用ChatGPT&#xff0c;Siri将利用ChatGPT的专业知识回答用户问题&#xff0c;并在查询之前征求用…

前端 Canvas 绘画 总结

目录 一、使用案例 1、基础使用案例 2、基本案例改为直接JS实现 二、相关资料 1、API教程文档 2、炫酷案例 一、使用案例 1、基础使用案例 使用Canvas的基本步骤&#xff1a; 1、需要一个canvas标签 2、需要获取 画笔 对象 3、使用canvas提供的api进行绘图 <!--…

高级 <HarmonyOS主题课>借助AR引擎帮助应用实现虚拟与现实交互的能力的课后习题

持而盈之&#xff0c;不如其已&#xff1b; 揣而锐之&#xff0c;不可长保。 金玉满堂&#xff0c;莫之能守&#xff1b; 富贵而骄&#xff0c;自遗其咎。 功成身退&#xff0c;天之道也。 VR (Virtual Reality): 虚拟现实技术 AR (Augmented Reality): 增强现实) XR.(Extend…

tp接口 入口文件 500 错误原因

一、描述 二、可能的原因 1、runtime目录没权限 2、关闭了Tp记录日志的功能 3、关闭debug调试模式 4、关闭了debug模式还是报错 一、描述 Thinkphp项目本地正常&#xff0c;上传到线上后静态文件访问正常&#xff0c;访问tp接口报500错误。 经调试发现&#xff0c;在php入…

解决:ros进行gazebo仿真,rviz没有显示传感器数据

目录 前言解决总结 前言 看了很多urdf、xacro文件的编写&#xff0c;每次看了都觉得自己会了&#xff0c;然后自己写一点&#xff0c;就是废物了。 在我这里的案例是&#xff0c;我在一个大方块上面&#xff0c;添加了两个VLP-16的雷达&#xff0c;然后我想获取雷达扫描的数据…

C语言 | Leetcode C语言题解之第546题移除盒子

题目&#xff1a; 题解&#xff1a; int dp[100][100][100];int calculatePoints(int* boxes, int l, int r, int k) {if (l > r) {return 0;}if (dp[l][r][k] 0) {int r1 r, k1 k;while (r1 > l && boxes[r1] boxes[r1 - 1]) {r1--;k1;}dp[l][r][k] calcu…

基于开源 AI 智能名片、S2B2C 商城小程序的用户获取成本优化分析

摘要&#xff1a;本文围绕用户获取成本&#xff08;CAC&#xff09;这一关键指标展开深入剖析&#xff0c;详细阐述其计算方式&#xff0c;并紧密结合开源 AI 智能名片与 S2B2C 商城小程序的独特性质&#xff0c;从多个维度探讨如何通过挖掘新的获客渠道、巧妙运用私域流量池等…

实践出真知:MVEL表达式中for循环的坑

目录标题 背景MVEL脚本(有问题的)MVEL脚本(正确的)结论分析 背景 需要从一个URL的拼接参数中解析出id的值并输出 比如&#xff1a; 存在URLhttps://xxxxxxxxxx?id999999&type123&name345 然后需要输出id999999 MVEL脚本(有问题的) 入参&#xff1a;parseThisUrlhttp…

【C#】使用.net9在C#中向现有对象动态添加属性

在 C# 中向现有对象动态添加属性并不像在 Python 或 JavaScript 中那样容易&#xff0c;因为 C# 是一种强类型语言。 但是&#xff0c;我们可以通过使用一些技术和库来实现这一点&#xff0c;例如扩展方法、字典等。本文将详细介绍如何在 C# 中实现这一点。ExpandoObject 方法 …

工作流初始错误 泛微提交流程提示_泛微协同办公平台E-cology8.0版本后台维护手册(11)–系统参数设置

工作流初始错误 泛微提交流程提示_泛微协同办公平台E-cology8.0版本后台维护手册(11)–系统参数设置...-CSDN博客 工作流初始错误 泛微提交流程提示_泛微OA 工作流WebService接口使用说明 工作流初始错误 泛微提交流程提示_泛微OA 工作流WebService接口使用说明-CSDN博客 工作…

如何有效销售和应用低代码软件?探索其市场机会与策略

随着技术的进步&#xff0c;企业对自动化和数字化的需求日益增加。低代码开发平台应运而生&#xff0c;成为企业实现快速应用程序开发的重要工具。然而&#xff0c;在市场上推广和应用低代码软件并非易事&#xff0c;需要深入了解客户需求&#xff0c;提供定制化的解决方案&…