时间限制:$2000ms$
空间限制:$256MB$
query
Given a permutation $p$ of length $n$, you are asked to answer $m$ queries, each query can be represented as a pair ($l,\ r$), you need to find the number of pair($i,\ j$) such that $l\le i < j\le r$ and $\min(p_i, p_j)=gcd(p_i, p_j)$.
Input
There is two integers $n$($1\le n\le 10^5$), $m$($1\le m\le 10^5$) in the first line, denoting the length of $p$ and the number of queries.
In the second line, there is a permutation of length $n$, denoting the given permutation $p$. It is guaranteed that $p$ is a permutation of length $n$.
For the next $m$ lines, each line contains two integer $l_i$ and $r_i$($1 \le l_i \le r_i \le n$), denoting each query.
Output
For each query, print a single line containing only one integer which denotes the number of pair($i,\ j$).
样例输入
1 | 3 2 |
样例输出
1 | 2 |
题意
给你一个 $n$ 的全排列,接下来有 $m$ 个查询,查询的是某个区间内有多少个数对($p_i,\ p_j$)($i<j$),这些数对满足条件 $gcd(p_i, p_j) = \min(p_i, p_j)$, 也就是这两个数之间存在倍数关系。
解决方案
唉,比赛的时候一直认为这是个纯粹的数论题,没往数据结构上想……
这题有个非常重要的条件,就是这个数组是 $n$ 的全排列!这样你才能够在 $O(nlogn)$ 的时间复杂度内把所有的数对全部筛选出来。
首先,我们先把所有的数对筛选出来,注意是坐标($i, j$),例如数组 $1,2,3,4,5$ ,先筛 $1$ 的,满足条件的数对是 ($1,2$)($1,3$)($1,4$)($1,5$),注意,数对里的数是这些数的坐标,而不是数本身。之后,把 $2,3,4,5$ 放到编号为 $1$ 的 $vector$ 里面,然后以此类推,把每个数往后的满足条件的数对都求出来并放进对应的 $vector$ 里面。可以先看一下这部分代码,这个时间复杂度是:
括号项是调和级数,和为 $\ln n$ 。
接下来有两种做法,一种是主席树在线查询,一种是线段树离线查询,思路是一样的,这里只讲前一种做法(没学过主席树的话建议学一下)。
首先考虑主席树存储什么,题目求满足条件的数对的数量,考虑存储区间和,那么这个和是什么呢?这得先清楚这棵主席树的建树过程。我们顺序扫描,每扫描一个点,就把它对应的 $vector$ 里面的所有下标,去主席树更新一下,准确的讲是这一点的值要 +1,现在明白主席树存储什么了吧?对于叶子节点,就是这个下标所处的点,能够满足条件的数对的数量。这里之所以要用主席树,就是因为它满足前缀和的性质,查询 ($l, r$) 可以用区间 ($1, r$) - ($1, l-1$) 。
这题有个坑爹的地方,由于共有 $n\ln n$ 个数对,每个点不止更新一次,而是要把它对应的 $vector$ 里面的所有点都更新一下,所以空间复杂度不是常规主席树的 $O(n\log n)$ ,而是 $O(n\log^2n)$ ,空间上卡的很紧…… ,总共就给了 $256MB$ 的空间,博主用了 $250MB$ ……
下面上代码
代码
1 |
|