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;
}
posted @ 2019-07-24 14:04  psimonw  阅读(230)  评论(0编辑  收藏  举报