牛客练习赛72 D - brz的函数 莫比乌斯反演

原题链接:https://ac.nowcoder.com/acm/contest/8282/D

目录

  • 题意
  • 化简
  • Code

题意

∑ i = 1 n ∑ j = 1 n μ ( i j ) \sum_{i=1}^{n}\sum_{j=1}^{n}\mu(ij) i=1nj=1nμ(ij)

化简

= ∑ i = 1 n ∑ j = 1 n μ ( i ) μ ( j ) [ g c d ( i , j ) = 1 ] =\sum_{i=1}^{n}\sum_{j=1}^{n}\mu(i)\mu(j)[gcd(i,j)=1] =i=1nj=1nμ(i)μ(j)[gcd(i,j)=1]

= ∑ i = 1 n ∑ j = 1 n μ ( i ) μ ( j ) ∑ t ∣ i , t ∣ j μ ( t ) =\sum_{i=1}^{n}\sum_{j=1}^{n}\mu(i)\mu(j)\sum_{t|i,t|j}\mu(t) =i=1nj=1nμ(i)μ(j)ti,tjμ(t)

= ∑ t = 1 n μ ( t ) ∑ i = 1 n / t ∑ j = 1 n / t μ ( i t ) μ ( j t ) =\sum_{t=1}^{n}\mu(t)\sum_{i=1}^{n/t}\sum_{j=1}^{n/t}\mu(it)\mu(jt) =t=1nμ(t)i=1n/tj=1n/tμ(it)μ(jt)

= ∑ t = 1 n μ ( t ) ∑ i = 1 n / t μ ( i t ) ∑ j = 1 n / t μ ( j t ) =\sum_{t=1}^{n}\mu(t)\sum_{i=1}^{n/t}\mu(it)\sum_{j=1}^{n/t}\mu(jt) =t=1nμ(t)i=1n/tμ(it)j=1n/tμ(jt)

设 F ( n , t ) = ∑ i = 1 n / t μ ( i t ) 设F(n,t)=\sum_{i=1}^{n/t}\mu(it) F(n,t)=i=1n/tμ(it)

= ∑ t = 1 n μ ( t ) F ( n , t ) 2 =\sum_{t=1}^{n}\mu(t)F(n,t)^2 =t=1nμ(t)F(n,t)2

到这里如果直接算是可以Tnlogn的,但考虑到有T组数据,所以预处理出所有答案,然后O(1)输出

换个角度,考虑每个F对答案的贡献,我们发现有些时候,n/t不同的n答案有时也是一样的,所以我们对于算出n的两端取值进行差分,O(nlogn)的复杂度

Code

#include 
using namespace std;
#define fi first
#define se second
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e6 + 100, M = 5e5 + 5, INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
ll prime[N], mu[N], k, ans[N];
bool is_prime[N];
inline void init(int n) {
    memset(is_prime, true, sizeof is_prime);
    mu[1] = 1;
    for (int i = 2; i < n; ++i) {
        if (is_prime[i]) prime[++k] = i, mu[i] = -1;
        for (int j = 1; j <= k && i * prime[j] < n; ++j) {
            is_prime[i * prime[j]] = false;
            if (i % prime[j] == 0) {
                break;
            } else {
                mu[i * prime[j]] = -mu[i];
            }
        }
    }
    for (int t = 1; t < n; t++) {
        ll tmp = 0;
        for (int i = t; i < n; i += t) {
            tmp += mu[i];
            int l = i;
            int r = min(n, l + t - 1);
            ans[l] += mu[t] * tmp * tmp;
            ans[r + 1] -= mu[t] * tmp * tmp;
        }
    }
    for (int i = 1; i < n; i++) ans[i] = ans[i-1] + ans[i];
}

void solve() {
    init(N);
    int T; cin >> T; while (T--) {
        int n; cin >> n;
        printf("%lld\n", ans[n]);
    }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

你可能感兴趣的:(数论)