zoukankan      html  css  js  c++  java
  • 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
    ", ans);
        }
    
        return 0;
    }
  • 相关阅读:
    单片机编程积累算法
    关于GSM基站定位
    GSM模块fibocom G510使用记录
    指爱 打字比赛记录
    硬件和软件工程师
    GPS模块启动模式说明
    阻容降压电路分析
    饮水机电路-工作剖析
    跑步,去
    day01 IT知识架构,操作系统简介
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7922968.html
Copyright © 2011-2022 走看看