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

    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

    题解

    由之前的 [HAOI 2011]Problem b

    令 $F(d)$ 为 $dmid gcd(i,j)$ 的数对 $(i,j)$ 个数, $f(d)$ 为 $d=gcd(i,j)$ 的数对 $(i,j)$ 个数。

    由题 $$F(k)=sum_{d=1}^{minleft{leftlfloorfrac{a}{k} ight floor,leftlfloorfrac{b}{k} ight floor ight}}f(kd)$$

    由莫比乌斯反演定理 $F(n)=sum_{nmid d} f(d)Rightarrow f(n)=sum_{nmid d} mu(frac{d}{n})F(d)$
    egin{aligned}Rightarrow f(k)&=sum_{d=1}^{minleft{leftlfloorfrac{a}{k} ight floor,leftlfloorfrac{b}{k} ight floor ight}}mu(d)F(kd)\&=sum_{d=1}^{minleft{leftlfloorfrac{a}{k} ight floor,leftlfloorfrac{b}{k} ight floor ight}}mu(d)cdotleftlfloorfrac{a}{kd} ight floorcdotleftlfloorfrac{b}{kd} ight floorend{aligned}

    显然对于此题 egin{aligned}ans&=sum_{isprime(p)}^{min{a,b}}sum_{d=1}^{minleft{leftlfloorfrac{a}{p} ight floor,leftlfloorfrac{b}{p} ight floor ight}}mu(d)cdotleftlfloorfrac{a}{pd} ight floorcdotleftlfloorfrac{b}{pd} ight floor\&=sum_{d=1}^{min{a,b}}sum_{isprime(p)}^{minleft{leftlfloorfrac{a}{d} ight floor,leftlfloorfrac{b}{d} ight floor ight}}mu(d)cdotleftlfloorfrac{a}{pd} ight floorcdotleftlfloorfrac{b}{pd} ight floorend{aligned}

    我们试着枚举 $pd$ $$ans=sum_{pd=1}^{min{a,b}}leftlfloorfrac{a}{pd} ight floorcdotleftlfloorfrac{b}{pd} ight floorcdotsum_{isprime(p')wedge p'mid(pd)}muleft(frac{pd}{p'} ight)$$

    我们令 $F(pd)=sum_{isprime(p')wedge p'mid(pd)}muleft(frac{pd}{p'} ight)$  $$ans=sum_{pd=1}^{min{a,b}}F(pd)cdotleftlfloorfrac{a}{pd} ight floorcdotleftlfloorfrac{b}{pd} ight floor$$

    只要我们预处理出 $F$ 的前缀就可以用数论分块来做了。

    预处理 $F$ 我们可以线性筛后枚举质数求(详见代码)。

     1 //It is made by Awson on 2018.1.22
     2 #include <set>
     3 #include <map>
     4 #include <cmath>
     5 #include <ctime>
     6 #include <queue>
     7 #include <stack>
     8 #include <cstdio>
     9 #include <string>
    10 #include <vector>
    11 #include <cstdlib>
    12 #include <cstring>
    13 #include <iostream>
    14 #include <algorithm>
    15 #define LL long long
    16 #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    17 #define Max(a, b) ((a) > (b) ? (a) : (b))
    18 #define Min(a, b) ((a) < (b) ? (a) : (b))
    19 #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    20 #define writeln(x) (write(x), putchar('
    '))
    21 #define lowbit(x) ((x)&(-(x)))
    22 using namespace std;
    23 const int N = 10000000;
    24 void read(int &x) {
    25     char ch; bool flag = 0;
    26     for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
    27     for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
    28     x *= 1-2*flag;
    29 }
    30 void write(LL x) {
    31     if (x > 9) write(x/10);
    32     putchar(x%10+48);
    33 }
    34 
    35 int F[N+5], a, b;
    36 int isprime[N+5], prime[N+5], tot = 0, mu[N+5];
    37 
    38 void get_F() {
    39     memset(isprime, 1, sizeof(isprime)); isprime[1] = 0, mu[1] = 1;
    40     for (int i = 2; i <= N; i++) {
    41     if (isprime[i]) prime[++tot] = i, mu[i] = -1;
    42     for (int j = 1; j <= tot && i*prime[j] <= N; j++) {
    43         isprime[i*prime[j]] = 0;
    44         if (i%prime[j]) mu[i*prime[j]] = -mu[i];
    45         else {mu[i*prime[j]] = 0; break; }
    46     }
    47     }
    48     for (int i = 1; i <= tot; i++) for (int j = 1, p = prime[i]; j*p <= N; j++) F[j*p] += mu[j];
    49     for (int i = 1; i <= N; i++) F[i] += F[i-1];
    50 }
    51 LL cal(int a, int b) {
    52     if (a > b) Swap(a, b); LL ans = 0;
    53     for (int i = 1, last; i <= a; i = last+1) {
    54     last = Min(a/(a/i), b/(b/i));
    55     ans += (LL)(F[last]-F[i-1])*(a/i)*(b/i);
    56     }
    57     return ans;
    58 }
    59 void work() {
    60     read(a), read(b); writeln(cal(a, b));
    61 }
    62 int main() {
    63     int t; read(t); get_F();
    64     while (t--) work();
    65     return 0;
    66 }
    Code1

    当然我们也可以利用函数 $F$ 的积性。线性筛的过程就把 $F$ 筛出来。设枚举的数为 $i$ ,质数为 $p$ :

    1. $pmid i$ , $F(ip)=mu(i)$ ;

    2. $p mid i$ , $F(ip)=mu(i)-F(i)$ 。

     1 //It is made by Awson on 2018.1.23
     2 #include <set>
     3 #include <map>
     4 #include <cmath>
     5 #include <ctime>
     6 #include <queue>
     7 #include <stack>
     8 #include <cstdio>
     9 #include <string>
    10 #include <vector>
    11 #include <cstdlib>
    12 #include <cstring>
    13 #include <iostream>
    14 #include <algorithm>
    15 #define LL long long
    16 #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    17 #define Max(a, b) ((a) > (b) ? (a) : (b))
    18 #define Min(a, b) ((a) < (b) ? (a) : (b))
    19 #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    20 #define writeln(x) (write(x), putchar('
    '))
    21 #define lowbit(x) ((x)&(-(x)))
    22 using namespace std;
    23 const int N = 10000000;
    24 void read(int &x) {
    25     char ch; bool flag = 0;
    26     for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
    27     for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
    28     x *= 1-2*flag;
    29 }
    30 void write(LL x) {
    31     if (x > 9) write(x/10);
    32     putchar(x%10+48);
    33 }
    34 
    35 int n, m; LL F[N+5];
    36 int isprime[N+5], prime[N+5], tot, mu[N+5];
    37 
    38 void get_F() {
    39     memset(isprime, 1, sizeof(isprime)); isprime[1] = 0; mu[1] = 1;
    40     for (int i = 2; i <= N; i++) {
    41     if (isprime[i]) prime[++tot] = i, mu[i] = -1, F[i] = 1;
    42     for (int j = 1; j <= tot && i*prime[j] <= N; j++) {
    43         isprime[i*prime[j]] = 0;
    44         if (i%prime[j]) mu[i*prime[j]] = -mu[i], F[i*prime[j]] = mu[i]-F[i];
    45         else {mu[i*prime[j]] = 0, F[i*prime[j]] = mu[i]; break; }
    46     }
    47     F[i] += F[i-1];
    48     }
    49 }
    50 LL cal(int n, int m) {
    51     if (n > m) Swap(n, m); LL ans = 0;
    52     for (int i = 1, last; i <= n; i = last+1) {
    53     last = Min(n/(n/i), m/(m/i));
    54     ans += (LL)(F[last]-F[i-1])*(n/i)*(m/i);
    55     }
    56     return ans;
    57 }
    58 void work() {
    59     read(n), read(m), writeln(cal(n, m));
    60 }
    61 int main() {
    62     int t; read(t); get_F();
    63     while (t--) work();
    64     return 0;
    65 }
    Code2
  • 相关阅读:
    bzoj 3262: 陌上花开
    hdu 5618 Jam's problem again
    bzoj 1176: [Balkan2007]Mokia
    bzoj 2683: 简单题
    Codevs 1080 线段树练习(CDQ分治)
    bzoj 3223: Tyvj 1729 文艺平衡树
    bzoj 1503: [NOI2004]郁闷的出纳员
    bzoj 1208: [HNOI2004]宠物收养所
    bzoj 1588: [HNOI2002]营业额统计
    bzoj 3224: Tyvj 1728 普通平衡树
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8327513.html
Copyright © 2011-2022 走看看