• BZOJ1101 [POI2007] Zap


    1101: [POI2007]Zap

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 2690  Solved: 1137
    [Submit][Status][Discuss]

    Description

      FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a
    ,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。

    Input

      第一行包含一个正整数n,表示一共有n组询问。(1<=n<= 50000)接下来n行,每行表示一个询问,每行三个
    正整数,分别为a,b,d。(1<=d<=a,b<=50000)

    Output

      对于每组询问,输出到输出文件zap.out一个正整数,表示满足条件的整数对数。

    Sample Input

    2
    4 5 2
    6 4 3

    Sample Output

    3
    2
    //对于第一组询问,满足条件的整数对有(2,2),(2,4),(4,2)。对于第二组询问,满足条件的整数对有(
    6,3),(3,3)。

    HINT

    Source

    【题解】

    莫比乌斯反演。

    下面转自http://blog.csdn.net/regina8023/article/details/43876363(侵删)

    先把题目转化为求x<=a/d,y<=b/d且gcd(x,y)=1的(x,y)有多少对。


    而莫比乌斯函数有一个性质是


    这里的n=1与gcd(x,y)=1相似。


    (下面引用自 iwtwiioi)



    如果直接枚举d来做会TLE,但是我们发现a'/d的值在d等于好多值得时候都是相同的。


    比如a'=100,那么d在[34,50]之间a'/d都是2。


    那么我们可以把连续的一段d一起来算(分块):


    设a'/d=x,那么最后一个a'/d=x的d=a'/x,所以这段连续的区间就是[d,a'/(a'/d)]


    结合b'/d,取个min就可以了。

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <cstdlib>
     5 #define min(a, b) ((a) < (b) ? (a) : (b))
     6 
     7 inline void read(long long &x)
     8 {
     9     x = 0;char ch = getchar(), c = ch;
    10     while(ch < '0' || ch > '9')c = ch, ch = getchar();
    11     while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
    12     if(c == '-')x = -x;
    13 }
    14 
    15 const long long MAXN = 50000 + 10;
    16 
    17 long long miu[MAXN << 1], t, n, m, k, bprime[MAXN << 1], prime[MAXN << 1], tot, v;
    18 
    19 void make_miu()
    20 {
    21     miu[1] = 1;
    22     for(register long long i = 2;i <= MAXN;++ i)
    23     {
    24         if(!bprime[i])
    25         {
    26             prime[++tot] = i;
    27             miu[i] = -1;
    28         }
    29         for(register long long j = 1;j <= tot && i * prime[j] <= MAXN;++ j)
    30         {
    31             bprime[i * prime[j]] = 1;
    32             if(i % prime[j] == 0)
    33             {
    34                 miu[i * prime[j]] = 0;
    35                 break;
    36             }
    37             miu[i * prime[j]] = -miu[i];
    38         }
    39     }
    40     for(register long long i = 1;i <= MAXN;++ i)miu[i] += miu[i - 1];
    41 }
    42 
    43 int main()
    44 {
    45     read(t);
    46     make_miu();
    47     for(;t;-- t)
    48     {
    49         read(n), read(m), read(k);
    50         n /= k, m /= k;
    51         long long ma = min(n, m);
    52         register long long ans = 0, x, y, end; 
    53         for(register long long d = 1;d <= ma;++ d)
    54         {
    55             //当前n/d = x  最后一个d = n/x   x:[d, n/(n/x)] 
    56             x = n/d, y = m/d;
    57             end = min(n/x, min(m/y, ma));
    58             ans += (miu[end] - miu[d - 1]) *  x * y;
    59             d = end;
    60         }
    61         printf("%lld
    ", ans);
    62     }
    63     return 0;
    64 }
    BZOJ1101
  • 相关阅读:
    详解扩展欧几里得算法(扩展GCD)
    NOIP 2012 同余方程
    NOIP 2011 观光公交
    NKOJ4330 逛公园
    NKOJ 7.7练习题A IP地址
    NKOJ3777 卡牌操作
    NKOJ3772 看电影
    NKOJ3765 k个最小和
    NKOJ3775 数列操作
    NKOJ3768 数列操作
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/7485387.html
Copyright © 2020-2023  润新知