SPOJ PGCD - Primes in GCD Table (好题! 莫比乌斯反演+分块求和优化)

78 篇文章 0 订阅
56 篇文章 0 订阅


PGCD - Primes in GCD Table

Johnny has created a table which encodes the results of some operation -- a function of two arguments. But instead of a boring multiplication table of the sort you learn by heart at prep-school, he has created a GCD (greatest common divisor) table! So he now has a table (of height a and width b), indexed from (1,1) to (a,b), and with the value of field (i,j) equal to gcd(i,j). He wants to know how many times he has used prime numbers when writing the table.

Input

First, t ≤ 10, the number of test cases. Each test case consists of two integers, 1 ≤a,b < 107.

Output

For each test case write one number - the number of prime numbers Johnny wrote in that test case.

Example

Input:
2
10 10
100 100
Output:
30
2791

Added by:Yash
Date:2009-06-12
Time limit:0.687s
Source limit:11111B
Memory limit:1536MB
Cluster:Cube (Intel Pentium G860 3GHz)
Languages:All except: ERL JS NODEJS PERL 6 VB.net
Resource:Codechef










题目链接:http://www.spoj.com/problems/PGCD/


题目大意:1 <= x <= n,1 <= y <= m,求gcd(x, y)为素数的对数


题目分析:和前一题比只是多了一个上界,难度立马变大

学习了这篇博客才解决了这题http://www.cnblogs.com/iwtwiioi/p/4132095.html


为满足的对数

为满足的对数

 那么,很显然,反演后得到

因为题目要求是为质数,那么我们枚举每一个质数,然后得到

pn1<=d<=n/pμ(d)×n/pd×m/pd

T=pd ,那么问题可以转换为:

pn1<=d<=n/pμ(d)×nT×mT

将问题转换为枚举T得:

T=1npnp|Tpμ(Tp)×nT×mT

化简得

T=1nnT×mTpnp|Tpμ(Tp)

g[x]=pnp|xpμ(xp)

那么原式变成

T=1nnT×mT×g[T]

那么我们只需要考虑如何计算g[x]即可!而且如果 ppT ,那么 g[x]=0

我们发现 g[x] 似乎可以在线性筛的时候预处理出? x=k×p,p 的情况,可得:

g[kp]={μ(k)μ(k)g[k]p|kpk

首先根据定义,此时

g[kp]=pnp|kppμ(kpp)

首先考虑 p|k 时,有 kp 质因子 p 的指数>=2

1、当 p=p ,那么约掉后还剩下 μ(k)

2、当 pp ,那么 p 的质数>=2,根据莫比乌斯函数的定义,为0

因此 1+2=μ(k)

考虑 pk 时,有 kp 质因子 p 的指数=1

1、当 p=p ,那么约掉后同样是 μ(k)

2、当 pp ,那么因为 μ 是积性函数,且 pkp 互质,那么得到 μ(p)μ(kp) ,然后提出和式。因为 μ(p)=1 ,而和式内的和恰好就是 g[k] 的定义,因此这种情况的个数为 g[k]

因此 1+2=μ(k)−g[k]

最后分块求和然后乘起来


#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int const MAX = 1e7 + 5;
int mob[MAX], p[MAX], g[MAX], sum[MAX];
bool noprime[MAX];

int Mobius()
{
    mob[1] = 1;
    int pnum = 0;
    for(int i = 2; i < MAX; i++)
    {
        if(!noprime[i])
        {
            p[pnum ++] = i;
            mob[i] = -1;
            g[i] = 1;
        }
        for(int j = 0; j < pnum && i * p[j] < MAX; j++)
        {
            noprime[i * p[j]] = true;
            if(i % p[j] == 0)
            {
                mob[i * p[j]] = 0;
                g[i * p[j]] = mob[i];
                break; 
            }
            mob[i * p[j]] = -mob[i];
            g[i * p[j]] = mob[i] - g[i];
        }
        sum[i] = sum[i - 1] + g[i];
    }
}

ll cal(int l, int r)
{
    ll ans = 0;
    if(l > r)
        swap(l, r);
    for(int i = 1, last = 0; i <= l; i = last + 1)
    {
        last = min(l / (l / i), r / (r / i));
        ans += (ll) (l / i) * (r / i) * (sum[last] - sum[i - 1]);
    }
    return ans;
}

int main()
{
    Mobius();
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int l, r;
        scanf("%d %d", &l, &r);
        printf("%lld\n", cal(l, r));
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值