zoukankan      html  css  js  c++  java
  • BZOJ2820 YY的GCD 【莫比乌斯反演】

    2820: YY的GCD

    Time Limit: 10 Sec Memory Limit: 512 MB
    Submit: 2398 Solved: 1269
    [Submit][Status][Discuss]
    Description

    神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对kAc这种
    傻×必然不会了,于是向你来请教……多组输入
    Input

    第一行一个整数T 表述数据组数接下来T行,每行两个正整数,表示N, M
    Output

    T行,每行一个整数表示第i组数据的结果
    Sample Input

    2

    10 10

    100 100

    Sample Output

    30

    2791

    HINT

    T = 10000

    N, M <= 10000000

    题解

    还是经典的莫比乌斯反演
    我们设f(n)表示gcd等于n的对数
    我们设F(n)表示n|gcd的对数
    则有
    F(n)=NnMn

    f(n)=n|dμ(dn)F(d)

    =n|dμ(dn)NnMn

    =Ni=1μ(i)NnMn

    ans=NpprimeNi=1μ(i)NnMn

    =NT=1NnMnNp|Tμ(Tp)

    对于前半部分NT=1NnMn我们可以分块O(2N)

    后半部分我们可以预处理,枚举每个质数以及它的倍数
    由于质数的个数大约是nlogn,而每个质数倍数的枚举均摊是logn的,加上线性筛,总的预处理复杂度O(n)

    总复杂度O(TN+N)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<bitset>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
    using namespace std;
    const int maxn = 10000005,maxm = 100005,INF = 1000000000;
    inline int RD(){
        int out = 0,flag = 1; char c = getchar();
        while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
        while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
        return out * flag;
    }
    bool isn[maxn];
    int prime[maxn],primei = 0,mu[maxn];
    LL A[maxn];
    void init(){
        mu[1] = 1;
        for (int i = 2; i <= 10000000; i++){
            if (!isn[i]) prime[++primei] = i,mu[i] = -1;
            for (int j = 1; j <= primei && i * prime[j] <= 10000000; j++){
                isn[i * prime[j]] = true;
                if (i % prime[j] == 0) {mu[i * prime[j]] = 0; break;}
                mu[i * prime[j]] = -mu[i];
            }
        }
        REP(i,primei) for (int j = 1; prime[i] * j <= 10000000; j++) A[prime[i] * j] += mu[j];
        REP(i,10000000) A[i] += A[i - 1];
    }
    int main(){
        init();
        int Tim = RD(),N,M;
        LL ans;
        while (Tim--){
            N = RD(); M = RD(); ans = 0; if (N > M) swap(N,M);
            for (int i = 1,nxt; i <= N; i = nxt + 1){
                nxt = min(N / (N / i),M / (M / i));
                ans += (A[nxt] - A[i - 1]) * (N / i) * (M / i);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    java类加载过程
    进程和线程
    Java对象的创建
    java异常—检查异常(checked exception)和未检查异常(unchecked exception)
    try...catch...finally语句块
    Mysql数据库索引
    java-生产者消费者模式
    解压字符串
    Java-break,continue,return用法
    归并排序-Java
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282755.html
Copyright © 2011-2022 走看看