bzoj2820 YY的GCD

2820: YY的GCD

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 2285  Solved: 1222
[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

分析:显然这道题是一道莫比乌斯反演的题.和bzoj2301很相似,只是这道题如果想要用那道题的方法还要枚举一个质数,再乘上根号的时间直接就爆炸了.

          考虑答案式子:,实际上就是枚举了一个质数p和p的倍数d来计算答案.考虑怎么求它.如果用bzoj2301的方法来求,那么μ函数中的式子要是一个分式才行,那么设T=pd,d=T/p,带入,把枚举倍数的放在一边,枚举约数的放在另一边,倍数从1开始枚举,就变形成了:,接下来就非常显然了,O(sqrt(n))就可以搞定了.只不过要在线性筛的时候预处理一下μ函数的前缀和,方法就是对于每一个质数,计算它对它的倍数的贡献,复杂度差不多是O(nlogn)级别的.

       一个非常常用的技巧:将求倍数的放在一边,将求约数的放在另一边,倍数从1开始枚举,很多题都会用到这个变形.

 

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;

const ll maxn = 1e7+5;

ll prime[1000010], tot, vis[10000010], mo[10000010], sum[10000010], T, ans, n, m;

void init()
{
    mo[1] = 1;
    for (ll i = 2; i <= maxn; i++)
    {
        if (!vis[i])
        {
            prime[++tot] = i;
            mo[i] = -1;
        }
        for (ll j = 1; j <= tot; j++)
        {
            ll t = i * prime[j];
            if (t > maxn)
                break;
            vis[t] = 1;
            if (i % prime[j] == 0)
            {
                mo[t] = 0;
                break;
            }
            mo[t] = -mo[i];
        }
    }
    for (ll i = 1; i <= tot; i++)
    {
        ll x = prime[i];
        for (ll j = x; j <= maxn; j += x)
            sum[j] += mo[j/x];
    }
    for (ll i = 1; i <= maxn; i++)
        sum[i] += sum[i - 1];
}

int main()
{
    init();
    scanf("%lld", &T);
    while (T--)
    {
        ans = 0;
        ll last = 0;
        scanf("%lld%lld", &n, &m);
        for (ll i = 1; i <= min(n, m); i = last + 1)
        {
            last = min(n / (n / i), m / (m / i));
            ans += (sum[last] - sum[i - 1]) * (n / i) * (m / i);
        }
        printf("%lld\n", ans);
    }

    return 0;
}

 

 

 

 

 

posted @ 2017-11-30 21:51  zbtrs  阅读(270)  评论(0编辑  收藏  举报