G2. Permutation Problem (Hard Version)
G2. Permutation Problem (Hard Version)
This is the hard version of the problem. The only difference is that in this version and the sum of for all sets of input data does not exceed .
You are given a permutation of length . Calculate the number of index pairs such that is divisible by without remainder.
A permutation is a sequence of integers, in which each integer from to occurs exactly once. For example, , , are permutations, while , , are not.
Input
Each test consists of several sets of input data. The first line contains a single integer () — the number of sets of input data. Then follows their description.
The first line of each set of input data contains a single integer () — the length of the permutation .
The second line of each set of input data contains distinct integers () — the permutation .
It is guaranteed that the sum of for all sets of input data does not exceed .
Output
For each set of input data, output the number of index pairs such that is divisible by without remainder.
Example
input
6
1
1
2
1 2
3
2 3 1
5
2 4 1 3 5
12
8 9 7 12 1 10 6 3 2 4 11 5
15
1 2 4 6 8 10 12 14 3 9 15 5 7 11 13
output
0
1
1
3
9
3
Note
In the first set of input data, there are no index pairs, as the size of the permutation is .
In the second set of input data, there is one index pair and it is valid.
In the third set of input data, the index pair is valid.
In the fourth set of input data, the index pairs , , and are valid.
解题思路
当固定 后,合法的 需要满足 ,为了避免枚举 ,令 ,。那么 就等价于 且 。
因此一种枚举的方法是,固定 后枚举 的倍数 ,统计 中有多少个相应的 满足 。但为了保证时间复杂度,我们不枚举 ,而是从 到 枚举 。同时开两个 std::vector
和 , 表示所有 对应的 , 表示所有 对应的 。
因此新的枚举方法是,固定 ,枚举 的倍数 ,枚举 中的元素并用哈希表统计出现次数。最后枚举 中每个元素的因子 ,把哈希表中 的出现次数累加到答案。
看上去好像有多重循环的枚举,但实际上整个过程的时间复杂度是 。先考虑整个过程枚举 中的元素的次数,容易知道 内的每个元素最多会被枚举 的因子个数次,由于 每个数的因子的总和大概是 级别,因此平均每个数有 个因子。所以 内的每个元素最多会被枚举 次,那么整个过程中所有元素会被枚举 次。
再考虑枚举所有 内的元素的因子的次数,本质就是枚举 中每个数的因子,也是 级别。
最后由于统计的对数是不考虑先后顺序的,因此每一对答案都会被统计两次,所以需要对统计的结果除以 。另外需要注意的是,如果有 ,在统计的时候会把 这一对也统计进来,因此需要一开始对答案减 。
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e5 + 5;
int a[N];
vector<int> d[N];
vector<int> p[N], q[N];
int cnt[N];
void solve() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
d[i].clear();
p[i].clear();
q[i].clear();
}
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j += i) {
d[j].push_back(i);
}
}
LL ret = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
if (a[i] % i == 0) ret--;
int d = __gcd(i, a[i]);
int x = i / d, y = a[i] / d;
p[x].push_back(y);
q[y].push_back(x);
}
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j += i) {
for (auto &x : q[j]) {
cnt[x]++;
}
}
for (auto &x : p[i]) {
for (auto &y : d[x]) {
ret += cnt[y];
}
}
for (int j = i; j <= n; j += i) {
for (auto &x : q[j]) {
cnt[x] = 0;
}
}
}
printf("%lld\n", ret / 2);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
参考资料
Codeforces Round 954 (Div. 3) Editorial:https://codeforces.com/blog/entry/130762
Codeforces Round 954 (Div. 3) A - G:https://zhuanlan.zhihu.com/p/705010951
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18269893
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2022-06-26 有限小数