zoukankan      html  css  js  c++  java
  • [POI 2007] Zap

    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=1101

    [算法]

             首先 , 问题可以转化为求GCD(x,y) = 1,x <= a / d , y <= b / d,的二元组个数

             令F(a,b,d)表示x <= a , y <= b , d | GCD(x,y)的二元组个数 , 显然 , 只需保证x和y都为d的倍数即可 , 因此 , F(a,b,d) = [a / d][b / d](其中,"[]"表示向下取整)

             那么 , 要求互质的二元组个数 , 可以通过容斥原理进行计算 :

             在没有限制的情况下 , 共有a * b对二元组 , 需要将答案减去公约数是2 , 3 , 5 , 7等素数的倍数的二元组 , 但这样会多减了如公约数为2且3的倍数的二元组 , 需要加上它。 

             不难发现 , Answer = sigma( miu(i) * F(a,b,i) )(1 <= i <= min(a,b) , miu为莫比乌斯函数)

             可以通过数论分块快速计算 , 时间复杂度 : O(T * (sqrt(A) + sqrt(B)) ( 其中,sqrt表示开根号) 

              

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 50010
    
    int T,a,b,d;
    int miu[MAXN],sum[MAXN];
    
    inline void sieve()
    {
            static bool visited[MAXN];
            for (int i = 1; i < MAXN; i++) 
            {
                    visited[i] = false;
                    miu[i] = 1;
            }
            for (int i = 2; i < MAXN; i++)
            {
                    if (visited[i]) continue;
                    miu[i] = -1;
                    for (int j = 2 * i; j < MAXN; j += i)
                    {
                            visited[j] = true;
                            if ((j / i) % i == 0) miu[j] = 0;
                            else miu[j] *= -1;
                    }        
            }    
            for (int i = 1; i < MAXN; i++) sum[i] = sum[i - 1] + miu[i];
    }
    inline int getsum(int l,int r)
    {
            return sum[r] - sum[l - 1];
    }
    inline int solve(int x,int y)
    {
            int gi;
            int ret = 0;
            for (int i = 1; i <= min(x,y); i = gi + 1)
            {
                    gi = min((x / (x / i)),(y / (y / i)));
                    ret += (x / i) * (y / i) * getsum(i,gi);        
            }    
            return ret;
    }
    
    int main() 
    {
            
            scanf("%d",&T);
            sieve();
            while (T--)
            {
                    scanf("%d%d%d",&a,&b,&d);
                    printf("%d
    ",solve(a / d,b / d));        
            }
            
            return 0;
        
    }
  • 相关阅读:
    WSL2
    坐标系变换
    Python websocket
    PAJ7620 IIC 通信
    Python中assert的使用
    Python中循环的使用
    Linux 生成指定大小文件
    SVN不显示log 显示1970年问题
    阿里云 CS实例 开机自运行脚本文件
    生成UDS安全算法DLL文件
  • 原文地址:https://www.cnblogs.com/evenbao/p/9575597.html
Copyright © 2011-2022 走看看