zoukankan      html  css  js  c++  java
  • NYOJ 1066 CO-PRIME(数论)

    CO-PRIME

    时间限制:1000 ms  |  内存限制:65535 KB
    难度:3
    描写叙述

    This problem is so easy! Can you solve it?

    You are given a sequence which contains n integers a1,a2……an, your task is to find how many pair(ai, aj)(i < j) that ai and aj is co-prime.

     

    输入
    There are multiple test cases.
    Each test case conatains two line,the first line contains a single integer n,the second line contains n integers.
    All the integer is not greater than 10^5.
    输出
    For each test case, you should output one line that contains the answer.
    例子输入
    3
    1 2 3
    例子输出
    3

    题意:给出n个正整数,求这n个数中有多少对互素的数。

    分析:莫比乌斯反演。

    此题中,设F(d)表示n个数中gcdd的倍数的数有多少对,f(d)表示n个数中gcd恰好为d的数有多少对,

    F(d)=f(n) (n % d == 0)

      f(d)=mu[n / d] * F(n) (n %d == 0)

    上面两个式子是莫比乌斯反演中的式子。

    所以要求互素的数有多少对。就是求f(1)

    而依据上面的式子能够得出f(1)=mu[n] * F(n)

    所以把mu[]求出来,枚举n即可了。当中mu[i]为i的莫比乌斯函数。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int MAXN = 1e5 + 10;
    typedef long long LL;
    int cnt[MAXN], pri[MAXN], num[MAXN], pri_num, mu[MAXN], vis[MAXN], a[MAXN];
    
    void mobius(int n)  //筛法求莫比乌斯函数
    {
        pri_num = 0;
        memset(vis, 0, sizeof(vis));
        vis[1] = mu[1] = 1;
        for(int i = 2; i <= n; i++) {
            if(!vis[i]) {
                pri[pri_num++] = i;
                mu[i] = -1;
            }
            for(int j = 0; j < pri_num; j++) {
                if(i * pri[j] > n) break;
                vis[i*pri[j]] = 1;
                if(i % pri[j] == 0) {
                    mu[i*pri[j]] = 0;
                    break;
                }
                mu[i*pri[j]] = -mu[i];
            }
        }
    }
    
    LL get(int x)
    {
        return (LL)x * (x-1) / 2;
    }
    
    int main()
    {
        mobius(100005);
        int n;
        while(~scanf("%d",&n)) {
            int mmax = 0;
            for(int i = 1; i <= n; i++) {
                scanf("%d",&a[i]);
                mmax = max(mmax, a[i]);
            }
            memset(cnt, 0, sizeof(cnt));
            memset(num, 0, sizeof(num));
            for(int i = 1; i <= n; i++) num[a[i]]++;
            for(int i = 1; i <= mmax; i++)
                for(int j = i; j <= mmax; j += i)
                    cnt[i] += num[j];
            LL ans = 0;
            for(int i = 1; i <= mmax; i++)
                ans += get(cnt[i]) * mu[i];
            printf("%lld
    ", ans);
        }
        return 0;
    }

  • 相关阅读:
    第十二周作业
    第十一周作业
    第十一次上机作业
    第十次上机作业
    第九周上机作业
    第八周作业
    第八次上机练习
    第七周作业
    第八周
    第六周作业
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5180333.html
Copyright © 2011-2022 走看看