loj6539. 奇妙数论题
题意
给出一个排列\(a\),求
\[\sum_{i = 1} ^ n \sum_{j = 1} ^ n (i, j) (a_i, a_j)
\]
题解
挂链跑路。
觉得自己太菜了
总之,遇到这种题目先把熟悉的部分提出来形成熟悉的形式,剩下的部分就是一个新问题。
(说实话,对于剩下的这个问题,感觉还是没有掌握精髓)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005, mod = 1e9 + 7;
int n;
int a[N], mu[N], phi[N], cnt[N];
int pr[N];
bool isp[N];
ll ans;
ll f[N];
vector <int> ds[N], st;
void sieve () {
memset(isp, 1, sizeof isp);
phi[1] = 1, mu[1] = 1;
for (int i = 2; i <= n; ++i) {
if (isp[i]) {
pr[++pr[0]] = i;
phi[i] = i - 1, mu[i] = -1;
}
for (int j = 1; j <= pr[0] && i * pr[j] <= n; ++j) {
isp[i * pr[j]] = 0;
if (i % pr[j] == 0) {
phi[i * pr[j]] = phi[i] * pr[j];
mu[i * pr[j]] = 0;
break;
}
phi[i * pr[j]] = phi[i] * phi[pr[j]];
mu[i * pr[j]] = -mu[i];
}
}
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= n; j += i) {
ds[j].push_back(i);
}
}
}
int main () {
scanf("%d", &n), sieve();
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; ++i) {
st.clear();
for (int j = i; j <= n; j += i) {
for (auto x : ds[a[j]]) {
++cnt[x], st.push_back(x);
}
}
for (auto x : st) {
f[i] += 1ll * phi[x] * cnt[x] % mod * cnt[x];
f[i] %= mod;
cnt[x] = 0;
}
}
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= n; j += i) {
ans += 1ll * i * mu[j / i] % mod * f[j];
ans %= mod;
}
}
printf("%lld\n", ans);
return 0;
}