[HAOI 2011] Problem b

[题目链接]

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

[算法]

         首先,满足a <= x <= b , c <= y <= d , GCD(x,y) = k的二元组对数可以转化为求 :

         1 <= x <= b , 1 <= y <= d , GCD(x,y) = k的二元组对数 

         -  1 <= x <= (a - 1) , 1 <= y <= d , GCD(x,y) = k的二元组对数

         - 1 <= x <= b , 1 <= y <= (c - 1) , GCD(x,y) = k的二元组对数

         + 1 <= x <= (a - 1) , 1 <= y <= (c - 1) , GCD(x,y) = k的二元组对数

         可以通过莫比乌斯函数 + 容斥原理解决 , 并用数论分块加速

         时间复杂度 : O(T ( sqrt(A) + sqrt(B) ) ( 其中,sqrt表示开根号)

[代码]

        

#include<bits/stdc++.h>
using namespace std;
#define MAXN 50010

int T,a,b,c,d,k;
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() 
{
        
        sieve();
        scanf("%d",&T);
        while (T--)
        {
                scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
                printf("%d\n",solve(b / k,d / k) - solve((a - 1) / k,d / k) - solve(b / k,(c - 1) / k) + solve((a - 1) / k,(c - 1) / k));
        }
        
        return 0;
    
}

 

posted @ 2018-09-03 21:32  evenbao  阅读(120)  评论(0编辑  收藏  举报