目录
- 翻译
- 思路
- 代码
- 关于G2的想法
翻译
原题链接
思路
数据很大,显然两边同时处理,所以要从
p
i
i
\frac{p_{i}}{i}
ipi下手。
要让
p
i
i
∗
p
j
j
\frac{p_{i}}{i} * \frac{p_{j}}{j}
ipi∗jpj是整数,每个
p
i
i
\frac{p_{i}}{i}
ipi都可以提供分子上的若干个因子,又需要别人提供分母上的所有因子。
对于每一个
p
i
p_{i}
pi,记
d
=
g
c
d
(
p
i
,
i
)
d=gcd(p_{i}, i)
d=gcd(pi,i),
P
=
p
i
d
,
Q
=
i
d
P=\frac{p_{i}}{d},Q=\frac{i}{d}
P=dpi,Q=di,我们记录所有二元对
(
x
,
y
)
(x, y)
(x,y),满足
x
∣
P
x|P
x∣P,
y
=
Q
y=Q
y=Q,意义是它能提供因子
x
x
x,又需要因子
y
y
y。
能和
p
i
i
\frac{p_{i}}{i}
ipi配对的数量就是之前记录的
(
y
,
x
)
(y, x)
(y,x)的数量。
由于要分解因子和使用 m a p map map,时间复杂度为 O ( n n l o g n ) O(n \sqrt{n}logn) O(nnlogn)。
代码
#include<bits/stdc++.h>
#define N 100005
using namespace std;
map<pair<int, int> , int> m;
int t, n, p[N];
int gcd(int x, int y) {
if(y == 0) return x;
return gcd(y, x%y);
}
int main() {
cin>>t;
while(t--) {
cin>>n;
long long ans = 0;
m.clear();
for(int i=1;i<=n;i++) scanf("%d", p+i);
for(int i=1;i<=n;i++) {
int d = gcd(i, p[i]);
int P = p[i] / d, Q = i / d;
for(int j=1;j*j<=P;j++) {
if(P % j == 0) {
ans += m[{Q, j}];
if(j * j != P) {
ans += m[{Q, P/j}];
}
}
}
for(int j=1;j*j<=P;j++) {
if(P % j == 0) {
m[{j, Q}] ++;
if(j * j != P) {
m[{P/j, Q}] ++;
}
}
}
}
cout<<ans<<endl;
}
}
关于G2的想法
先把G1的代码改一改数据范围丢进去再说,结果预料中的TLE没出现,内存先爆了。这也正常,最多花多少内存不会算 ,但肯定是map花了太多内存。然后想了点办法:
(1)用swap方法彻底释放map的内存。
(2)注意到只有存在一个
i
i
i需要对应的
Q
Q
Q,我们才在
x
=
Q
且
x
∣
P
j
x=Q且x|P_{j}
x=Q且x∣Pj时记录下
(
x
,
y
)
(x, y)
(x,y)。而这样的
Q
Q
Q最多只有
n
n
n个。所以在记录前判断一下。
(3)在读取map中的数据之前判断一下数据是否在map中。
效果不错,MLE变TLE了,也就是说时间复杂度也得改,这个 l o g log log不能要。
然后map其实就是用来计数的,所以我想到了hash,手写肯定不行,又得MLE,于是用上了unordered_map。
然后调了半天,先是C++版本不行,然后是没有内置的关于pair的映射,要重定义一下,最后好不容易编译过了,还是TLE。
后面试了一下开long long避免哈希冲突地太厉害,没什么用。
总之就是裂开了,代码放下面,有哪位大佬能救一下的或者指出原因的欢迎评论QwQ。
#include<bits/stdc++.h>
#define N 500005
using namespace std;
namespace std {
template<> struct hash<pair<int, int> > {
size_t operator()(const pair<int, int>& p) const {
return hash<int>()(p.first) ^ hash<int>()(p.second);
}
};
}
unordered_map<pair<int, int> , int> m;
int t, n, p[N];
bool needed[N];
inline int gcd(int x, int y) {
if(y == 0) return x;
return gcd(y, x%y);
}
int main() {
cin>>t;
while(t--) {
scanf("%d", &n);
long long ans = 0;
unordered_map<pair<int, int>, int>().swap(m); // 可以清空内存
for(int i=1;i<=n;i++) scanf("%d", p+i);
for(int i=1;i<=n;i++) {
int d = gcd(i, p[i]);
int P = p[i] / d, Q = i / d;
needed[Q] = true;
}
for(int i=1;i<=n;i++) {
int d = gcd(i, p[i]);
int P = p[i] / d, Q = i / d;
for(int j=1;j*j<=P;j++) {
if(P % j == 0) {
if(m.find({Q, j}) != m.end()) ans += m[{Q, j}];
if(j * j != P) {
if(m.find({Q, P/j}) != m.end()) ans += m[{Q, P/j}];
}
}
}
for(int j=1;j*j<=P;j++) {
if(P % j == 0) {
if(needed[j]) m[{j, Q}] ++;
if(j * j != P) {
if(needed[P/j]) m[{P/j, Q}] ++;
}
}
}
}
for(int i=1;i<=n;i++) {
int d = gcd(i, p[i]);
int P = p[i] / d, Q = i / d;
needed[Q] = false;
}
printf("%d\n", ans)
}
}