• BZOJ 2301: [HAOI2011]Problem b(莫比乌斯反演)


    http://www.lydsy.com/JudgeOnline/problem.php?id=2301

    题意:
    对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。

    思路:

    先简单介绍一下莫比乌斯反演在数论中的作用:

    那么怎么做这道题呢?

    接下来我们只需要枚举d就可以了,但是这里还有一个可以优化的地方,我们依次+1枚举d的时候,有时候n/d和m/d是不会改变的,比如说现在n=m=,那么d=3,4,5时n/d和m/d都是不变的,这样一来的话我们可以分块处理,需要计算一下莫比乌斯的前缀和,就可以将3,4,5的值一起计算了,这样一来,枚举的数量将大大减小。具体看代码。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<sstream>
     6 #include<vector>
     7 #include<stack>
     8 #include<queue>
     9 #include<cmath>
    10 #include<map>
    11 #include<set>
    12 using namespace std;
    13 typedef long long ll;
    14 typedef pair<int,int> pll;
    15 const int INF = 0x3f3f3f3f;
    16 const int maxn = 1e5 + 5;
    17 
    18 int a, b, c, d, k;
    19 
    20 bool check[maxn];
    21 int prime[maxn];
    22 int mu[maxn];
    23 int sum[maxn];
    24 
    25 void Moblus()
    26 {
    27     memset(check, false, sizeof(check));
    28     mu[1] = 1;
    29     int tot = 0;
    30     for (int i = 2; i <= maxn; i++)
    31     {
    32         if (!check[i])
    33         {
    34             prime[tot++] = i;
    35             mu[i] = -1;
    36         }
    37         for (int j = 0; j < tot; j++)
    38         {
    39             if (i * prime[j] > maxn)
    40             {
    41                 break;
    42             }
    43             check[i * prime[j]] = true;
    44             if (i % prime[j] == 0)
    45             {
    46                 mu[i * prime[j]] = 0;
    47                 break;
    48             }
    49             else
    50             {
    51                 mu[i * prime[j]] = -mu[i];
    52             }
    53         }
    54     }
    55     return ;
    56 }
    57 
    58 int solve(int n, int m)
    59 {
    60     if(n>m)  swap(n,m);
    61     int ans=0;
    62 
    63     for(int i=1,last=0;i<=n;i=last+1)
    64     {
    65         last=min(n/(n/i),m/(m/i));  //分块处理
    66         ans+=(sum[last]-sum[i-1])*(n/i)*(m/i);
    67     }
    68     return ans;
    69 }
    70 
    71 
    72 int main()
    73 {
    74     //freopen("in.txt","r",stdin);
    75     int T;
    76     Moblus();
    77     sum[0]=0;
    78     for(int i=1;i<=maxn;i++)  sum[i]=sum[i-1]+mu[i];
    79 
    80     scanf("%d",&T);
    81     while(T--)
    82     {
    83         scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
    84         printf("%d
    ",solve(b/k,d/k)-solve(b/k,(c-1)/k)-solve((a-1)/k,d/k)+solve((a-1)/k,(c-1)/k));
    85     }
    86     return 0;
    87 }
  • 相关阅读:
    因为数据库无法大写循环所有要使用shell
    mysql动态扩容调研
    MySQL扩容
    数据库死锁及解决死锁问题
    SQL数据库常见故障及解决方法
    通过Ajax方式上传文件(input file),使用FormData进行Ajax请求
    Ajax方式上传文件
    高并发解决方案--负载均衡
    对TCP/IP协议的深入浅出总结
    常用的php开发工具有哪些?
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/7250318.html
Copyright © 2020-2023  润新知