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\n",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 }
时间: 2024-08-21 16:19:49

BZOJ 2301: [HAOI2011]Problem b(莫比乌斯反演)的相关文章

bzoj 2301: [HAOI2011]Problem b 莫比乌斯反演

2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 3679  Solved: 1648[Submit][Status][Discuss] Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Outp

bzoj 2301: [HAOI2011]Problem b mobius反演 RE

http://www.lydsy.com/JudgeOnline/problem.php?id=2301 设f(i)为在区间[1, n]和区间[1, m]中,gcd(x, y) = i的个数. 设F(i)为在区间[1, n]和区间[1, m]中,gcd(x, y) % i == 0的个数,很简单的公式就是floor(n / i) * floor(m / i) 可知gcd(x, y) = k * i也属于F(i)的范围,所以可以反演得到f(i)的表达式. 算一次复杂度O(n),而且询问区间的时候要

BZOJ 2301: [HAOI2011]Problem b(莫比乌斯反演 + 容斥原理 + 分块优化)

传送门 Problem 2301. – [HAOI2011]Problem b 2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 3671  Solved: 1643[Submit][Status][Discuss] Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input

BZOJ 2301 [HAOI2011]Problem b (容斥+莫比乌斯反演+分块优化 详解)

2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MB Submit: 2096  Solved: 909 [Submit][Status][Discuss] Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Out

BZOJ 2301([HAOI2011]Problem b-mobius反演)

2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MB Submit: 2170  Solved: 934 [Submit][Status][Discuss] Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Out

[BZOJ 2301] [HAOI2011] Problem b

2301: [HAOI2011]Problem b Time Limit: 50 SecMemory Limit: 256 MB Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Output 共n行,每行一个整数表示满足要求的数对(x,y)的个数 Sample Input 2 2 5 1 5

BZOJ 2301 HAOI2011 Problem b 容斥原理+莫比乌斯反演

题目大意:多次询问有多少个数对(x,y)满足a<=x<=b,c<=y<=d,且GCD(x,y)=k 首先利用容斥原理将询问分解 问题转化为求有多少个数对(x,y)满足x<=m,y<=n,且GCD(x,y)=k 这里就可以利用到莫比乌斯反演: 我们令F(d)为GCD(x,y)=d且x<=m,y<=n的数对数 f(d)为d|GCD(x,y)且x<=m,y<=n的数对数 那么显然有F(d)=(n/d)*(m/d) 但是直接套用公式还是O(n^2)级别的

bzoj 2301 [HAOI2011]Problem b(莫比乌斯反演+分块优化)

题意:对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. 1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000 思路:莫比乌斯反演,ans=solve(b/k,d/k)-solve((a-1)/k,d/k)-solve(b/k,(c-1)/k)+solve((a-1)/k,(c-1)/k) 代码1:超时. #include<iostream> #include&l

BZOJ2301: [HAOI2011]Problem b 莫比乌斯反演

分析:对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. 然后对于求这样单个的gcd(x,y)=k的,我们通常采用莫比乌斯反演 但是,时间复杂度是O(n*(n/k))的,当复杂度很坏的时候,当k=1时,退化到O(n^2),超时 然后进行分块优化,时间复杂度是O(n*sqrt(n)) #include<cstdio> #include<cstring> #include<queue