zoukankan      html  css  js  c++  java
  • [BZOJ2820]YY的GCD

    2820: YY的GCD

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

    由对称性,不妨设$nle m$

    那么$ans=sum_{left(p ight)IsPrime}sum_{i=1}^nsum_{j=1}^mleft[gcdleft(i,j ight)=p ight]$

    由其它一些经典的题目(比如[POI2007]ZAP)很轻易地可以得到

    $ans=sum_{left(p ight)IsPrime}sum_{d=1}^{lfloorfrac{n}{p} floor}muleft(d ight)lfloorfrac{n}{pd} floorlfloorfrac{m}{pd} floor$

    由于在前$n$个数中质数的个数约为$frac{n}{lnn}$个

    那么即使是加上了分块优化时间复杂度也是$Oleft(frac{nsqrt{n}}{lnn} ight)$肯定会TLE

    考虑设$pd=T$

    那么$ans=sum_{T=1}^{n}lfloorfrac{n}{T} floorlfloorfrac{m}{T} floorsum_{pmid T}muleft(frac{T}{p} ight)$

    那么加上分块优化和前缀和处理后单次询问的时间复杂度就是$Oleft(sqrt{n} ight)$

    总时间复杂度$Oleft(Tsqrt{n} ight)$

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn = 10000000 + 10;
    bool mark[maxn] = {0};
    int pri[664580], prn = 0;
    int mu[maxn], sum[maxn];
    void shai(){
        mu[1] = 1;
        for(int i = 2; i < maxn; i++){
            if(!mark[i]){
                mu[i] = -1;
                pri[++prn] = i;
            }
            for(int j = 1; j <= prn && i * pri[j] < maxn; j++){
                mark[i * pri[j]] = true;
                if(i % pri[j] == 0){
                    mu[i * pri[j]] = 0;
                    break;
                }
                else mu[i * pri[j]] = -mu[i]; // = mu[pri[j]] * mu[i]
            }
        }
        for(int i = 1; i <= prn; i++)
            for(int j = 1; j * pri[i] < maxn; j++) sum[pri[i] * j] += mu[j];
        sum[0] = 0;
        for(int i = 1; i < maxn; i++)
            sum[i] += sum[i - 1];
    }
    int main(){
        shai();
        int T, n, m;
        ll ans;
        scanf("%d", &T);
        while(T--){
            scanf("%d %d", &n, &m);    
            if(n > m) swap(n, m);
            ans = 0;
            for(int p, i = 1; i <= n; i = p + 1){
                p = min(n / (n / i), m / (m / i));
                ans += (ll) (sum[p] - sum[i - 1]) * (n / p) * (m / p);
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    什么是32位汇编的flat平坦内存模式
    oracle随机操作
    网线8根排列顺序
    vb创建NT服务
    函数声明后面加个stdcall是什么意思
    一些基础问题。
    ArcGIS Server中地图打印的实现
    添加BaseCommand 和Base Tool 的注意事项
    获取字符串中的某个子字符串
    AE, C#,按纸张打印地图
  • 原文地址:https://www.cnblogs.com/ruoruoruo/p/7678296.html
Copyright © 2011-2022 走看看