[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为莫比乌斯函数)

[代码]

          

#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\n",solve(a / d,b / d));        
        }
        
        return 0;
    
}

猜你喜欢

转载自www.cnblogs.com/evenbao/p/9575597.html