The 2021 ICPC Asia Nanjing Regional Contest (GYM103470)

A

签到题,略。

C

Description

给定一个长度为\(n\)序列和一个整数\(k\),你可以选择给序列的某一段加上\(k\),要求最大化众数的出现次数。

\(n\le 10^6\), \(-10^6 \le a_i, k \le 10^6\)

Solution

发现权值范围不大,想到对于权值进行枚举。每次枚举\(x,x+k\),找到所有\(x\)\(x+k\)的位置,我们需要在其中选择一段将\(x\)变成\(x+k\)\(x+k\)变成\(x+2k\)\(+k\)前的答案即为\(x+k\)的出现次数。将\(x\)视为\(1\)\(x+k\)视为\(-1\),题目转化为求这个序列的最大子段和,加上\(x+k\)的出现次数即为\(+k\)之后\(x+k\)最多可能的出现次数。

注意\(k=0\)的情况和最后答案不需要\(+k\)的情况。

D

Description

给定一段代码:

for (int i = 1; i <= n; ++ i)
    for (int j = 1; j <= n; ++ j)
        if (a[i] < a[j]) swap(a[i], a[j]);

给定序列\(a_i\),问对于\(a_i\)的每一个前缀,执行这段代码的swap次数。

\(\sum n\le 10^6\)

Solution

在进行了第一轮交换之后,相当于一个极长上升子序列进行了轮换,之后的第\(i\)轮交换会保证前\(i\)个数是递增的,故第\(i+1\)轮的交换次数即为前\(i\)个数里比\(a_{i+1}\)大的数里有多少种不同的数。

  • 对于不属于极长上升子序列中的数,在第一轮交换前后的左边比它大的数的个数是不变的;
  • 对于属于该子序列中的数,在第一轮会进行一次交换,在它所属的那一轮也会进行一次交换,所以对答案有2的贡献。

如果存在相同数字,则需另外考虑:

  • 一方面,对于等于极长上升子序列中某个数\(a_i\)的数\(a_j\),在原序列上考虑前面大于\(a_j\)的数的个数时并不会考虑到\(a_i\),但是在进行第一轮交换之后,\(a_i\)会被换到后面去,取而代之的是全序列最大的那个数;
  • 另一方面,若\(a_i = a_j\)\(i<j\),对于\(k>j\)\(a_k<a_j\),我们统计有多少个不同的数大于\(a_k\)时,\(a_i\)\(a_j\)被看作了同一个,但是进行了第一轮交换之后这两个位置都会有贡献。

E

Description

有一个长度为\(n\)的序列,对其进行\(m\)个操作,每次将\(a_{l_i},\dots, a_{r_i}\)加上\(x_i\)。我们设第\(j\)次操作后,\(a_i\)的值为\(a_{i,j}\)。给出\(q\)个询问\(l_i,r_i,x_i,y_i\),要求算出:

\[\sum_{i=l_k}^{r_k} \sum_{j=x_k}^{y_k} a_{i,j}^2 \]

答案对\(10^9+7\)取模。(\(n,m,q\le 5\times 10^4\)

Solution

我们对于每个询问进行拆解,变成\(1,l_i-1,x_i,y_i\)\(1,r_i,x_i,y_i\)两个询问分别挂在对应的时间点上。我们按时间顺序依次处理每个操作,问题变成如何维护区间历史版本平方和。

考虑用线段树维护,对于当前时间点\(t\)和一个线段树节点表示的区间\([l,r]\),我们设:

\[\begin{aligned} A &= r - l + 1 \\ B &= \sum_{i=l}^r a_{i,t} \\ C &= \sum_{i=l}^r a_{i,t}^2 \\ D &= \sum_{j=0}^t \sum_{i=l}^r a_{i,j}^2 \end{aligned} \]

设时间点\(t-1\)的区间信息对应为\(A',B',C',D'\),时间点\(t\)时这个区间加上了\(x\),那么有:

\[\begin{aligned} A &= r - l + 1 = A' \\ B &= (r-l+1)x + \sum_{i=l}^r a_{i,t} = xA'+B' \\ C &= \sum_{i=l}^r (a_{i,t}+x)^2 = \sum_{i=l}^r (a_{i,x}^2 + x^2 + 2a_{i,t}x) = x^2A'+2xB'+C' \\ D &= D' + C = x^2A'+2xB'+C' + D' \end{aligned} \]

将转移表示成矩阵的形式,即:

\[\left(\begin{matrix} A' & B' & C' & D' \end{matrix}\right) \left(\begin{matrix} 1 & x & x^2 &x^2 \\ 0 & 1 & 2x & 2x \\ 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 1 \end{matrix}\right) = \left(\begin{matrix} A & B & C & D \end{matrix}\right) \]

对于线段树,维护\(A,B,C,D\)和一个矩阵tag即可。(注意,无论是否修改,每个点都需要累加历史版本和,所以需要另外添加\((0,l_i-1,0)\)\((r_i+1,n,0)\)两组修改)

一些常数优化:两个对角线为1上三角矩阵相乘的结果仍然时对角线为1的上三角矩阵,所以需要考虑的只有右上角6个数。

启发:

  1. 解决线段树历史版本的一个新的思路;

  2. 对于线段树维护多个量且量与量之间有线性转移关系的问题,可以考虑用矩阵乘法解决。

H

Description

给定一棵以1为根的树,每个节点有一个权值\(a_i\)。从\(1\)开始遍历这棵树,每到达一个节点,它周围的点的权值在\(t_i\)个单位时间内就会消失,我们希望取到最大权值和。

\(\sum n\le 10^6, 1\le t_i\le 3\)

Solution

发现\(t_i\)最大只有3,也就是说我们最多允许向某一个子节点走了一步后立刻返回、然后踩点到达另外一个\(t_i\)为3的子节点。

\(f_u\)表示不考虑节点\(u\)本身,子树内可以取到的最大权值是多少。

对于每个节点\(u\)有两种选择:

  • 选择一个子节点\(v\),并往该子树走,此时相当于可以取到\(v\)的权值而放弃了\(u\)的其它子节点的权值

    \[f_u = s_u + \max_v a_v \]

  • 选择一个子节点\(v_1\),走到该位置后立刻返回,然后选择另外一个子节点\(v_2\),并往该子树走,此时相当于取到了\(v_1\)\(v_2\)而放弃了\(u\)的其它子节点和\(v_1\)的其它子节点

    \[f_u = s_{v_1} + a_{v_1} + (s_u - f_{v_1}) + a_{v_2} \]

(其中\(s_u = \sum_v f_v\)

最后的答案即为\(f_1+a_1\)

I

Description

平面直角坐标系中有\(y=0\)\(y=H\)两条边界,有\(n\)个障碍,坐标为\((x_i,y_i)\);有\(m\)个金币,坐标为\((x_i', y_i')\)。从\((0,0)\)出发,初始方向为\(\vec{v} = (1,1)\),如果碰到边界或者木桩,\(v_y\)变成相反数。

你可以选择删掉一些木桩,问最多可以拿到多少个金币。

\(\sum n, \sum m \le 5\times 10^5\)

Solution

在没有木桩的情况下,\((x-y+2H)\bmod 2H = k\)且方向为\((1,1)\)的状态以及\((x+y) \bmod 2H = k\)且方向为\((1,-1)\)的状态是同一条路径上的,一共有\(2H\)条不同的路径。

我们以横坐标以及在哪一条路径上表示状态来进行转移(即对于每个横坐标,不同的纵坐标和两个方向组合起来就是\(2H\)条不同的路径)。

若状态所在坐标存在金币,则答案+1;若状态所在坐标存在障碍,也就是说可以选择这个位置是否转向,那么处于这个位置的两条路径都可以取到二者的较大值。

(不要忘了只能从\((0,0)\)出发)

J

Description

给定二元组\((a,b)\),有以下三种操作:

  • \(a,b\)同时加\(1\)
  • \(a,b\)同时减\(1\)
  • \(a,b\)同时除一个质因子

要求通过上述操作将\(a,b\)中的其中一个变成\(1\),求最少操作次数。

\(a,b\le 10^9\)

Solution

不妨假设\(a<b\)

易知每次除的质因子一定是\(b-a\)的引子。我们枚举除因子的顺序,每次如果不能整除,就通过+1或者-1来调整。

我们考虑\(a\)\(b-a\)表示搜索的状态,\(b-a\)一共有因子个数个;若已知\(b-a\),我们就知道\(a\)被哪些质因子除过,而且要么是除以这些因子之积向下取整,要么是向上取整,所以总状态数也是因子个数个的,故暴搜可过。

M

签到题,注意\(n=1\)的情况和所有\(a_i\)全部相等、最大值最小值指定为同一个位置的情况。

posted @ 2022-03-13 16:19  Hany01  阅读(155)  评论(0编辑  收藏  举报