hdu6053(莫比乌斯+容斥+分块)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6053

题意: 给出一个含 n 个元素的 a 数组, 求 bi <= ai 且 gcd(b1, ..., bn) >= 2 的 b 数组的数目;

思路: 首先想到的方法是枚举 gcd, 对于每个 gcd x 的情况, 将所有 bi / x 连乘, 然后将所有 gcd 的情况累加一下就能的到答案了 .

然而其时间复杂度为 O(t * min(a) * n), 铁定 tle;

对于后面连乘部分是可以优化一下的 . 把 a 数组元素装到一个桶里面, 然后枚举 gcd 时按照 ai / gcd 的值分下块,

对于区间 [gcd * k, gcd * (k + 1 ) - 1], 显然区间内的值除 gcd 的商都为 k, 若 a 中有 cnt 个元素处于该区间, 那么该块内的 b 数组元素有 k^cnt 种选择方案,

再将不同块的方案数乘起来就是当前 gcd 对答案的贡献了 .

然而上面还会出现重复计算(个人感觉这个有点难理解):

对于不能分解成不同素数乘积形式的 gcd, 在第一次计算其中多次出现的素因子作 gcd 时已经计算过了, 所以不累加到答案上 .

对于能分解成不同素数乘积形式的 gcd, 其中重复计算的我们可以用容斥去重, 奇加偶减 .

可以发现这和 moblus 函数很相近, 对与不能分解成不同素数乘积形式的数, 其 mu 值为 0, 对于能分解成不同素数乘积形式的数, 若其长度为奇数, mu 值为 -1, 长度为偶数则 mu 值为 1, 恰好与容斥的奇加偶减相反, 所以给 mu 加个负号即可 .

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define ll long long
 5 using namespace std;
 6
 7 const int mod = 1e9 + 7;
 8 const int MAXN = 1e5 + 10;
 9
10 bool check[MAXN];
11 int prime[MAXN], mu[MAXN], vis[MAXN << 1];
12
13 void Moblus(void){
14     memset(check, false, sizeof(check));
15     int tot = 0;
16     mu[1] = 1;
17     for(int i = 2; i < MAXN; i++){
18         if(!check[i]){
19             prime[tot++] = i;
20             mu[i] = -1;
21         }
22         for(int j = 0; j < tot && i * prime[j] < MAXN; j++){
23             check[i * prime[j]] = true;
24             if(i % prime[j] == 0){
25                 mu[i * prime[j]] = 0;
26                 break;
27             }else mu[i * prime[j]] = -mu[i];
28         }
29     }
30 }
31
32 ll get_pow(ll x, int n){
33     ll ans = 1;
34     while(n){
35         if(n & 1) ans = ans * x % mod;
36         x = x * x % mod;
37         n >>= 1;
38     }
39     return ans;
40 }
41
42 int main(void){
43     Moblus();
44     int t, n, x;
45     scanf("%d", &t);
46     for(int cas = 1; cas <= t; cas++){
47         memset(vis, 0, sizeof(vis));
48         int mi = MAXN, mx = - MAXN;
49         scanf("%d", &n);
50         for(int i = 0; i < n; i++){
51             scanf("%d", &x);
52             vis[x] += 1;
53             mi = min(mi, x);
54             mx = max(mx, x);
55         }
56         for(int i = 1; i < (MAXN << 1); i++){//注意范围
57             vis[i] += vis[i - 1];
58         }
59         ll ans = 0;
60         for(int i = 2; i <= mi; i++){
61             ll cnt = 1;
62             if(mu[i]){
63                 for(int j = i; j <= mx; j += i){
64                     cnt = (cnt * get_pow((ll)(j / i), vis[j + i - 1] - vis[j - 1])) % mod;
65                 }
66             }
67             ans = (ans - cnt * mu[i] + mod) % mod;
68         }
69         printf("Case #%d: %lld\n", cas, ans);
70     }
71     return 0;
72 }

时间: 2024-10-11 02:10:20

hdu6053(莫比乌斯+容斥+分块)的相关文章

BZOJ2440(完全平方数)二分+莫比乌斯容斥

题意:完全平方数是指含有平方数因子的数.求第ki个非完全平方数. 解法:比较明显的二分,getsum(int middle)求1-middle有多少个非完全平方数,然后二分.求1-middle的非完全平方数个数可以用总数减掉完全平方数个数.计算完全平方数的个数用容斥: 首先加上n/(2*2)+n/(3*3)+n/(5*5)+n/(7*7)...+...然后减掉出现两次的,然后加上三次的...奇加偶减.这就是mou的原型,用mou数组计算很简单: 代码: /********************

HihoCoder - 1867: GCD (莫比乌斯容斥)

Sample Input 6 1 6 2 5 3 4 Sample Output 10 You are given a {1, 2, ..., n}-permutation a[1], a[2], ..., a[n]. How many pairs of integers (i, j) satisfy 1 ≤ i ≤ j ≤ n and gcd(i, j) = gcd(a[i], a[j]) = 1? Here gcd means greatest common divisor. Input F

BZOJ2440(全然平方数)二分+莫比乌斯容斥

题意:全然平方数是指含有平方数因子的数.求第ki个非全然平方数. 解法:比較明显的二分,getsum(int middle)求1-middle有多少个非全然平方数,然后二分.求1-middle的非全然平方数个数能够用总数减掉全然平方数个数.计算全然平方数的个数用容斥: 首先加上n/(2*2)+n/(3*3)+n/(5*5)+n/(7*7)...+...然后减掉出现两次的,然后加上三次的...奇加偶减.这就是mou的原型,用mou数组计算非常easy: 代码: /*****************

ACdreamoj1114(Number theory)莫比乌斯容斥

http://passport.baidu.com/?business&un=%E7%BE%8E%E5%A5%B3%E6%89%BE%E6%9C%8D%E5%8A%A1%E6%B9%98%E4%B9%A1#0 http://passport.baidu.com/?business&un=%E6%89%BE%E7%94%B5%E8%AF%9D%E8%8C%B6%E9%99%B5%E7%BE%8E%E5%A5%B3#0 http://passport.baidu.com/?business&a

JZYZOJ1518 [haoi2011]b 莫比乌斯反演 分块 容斥

http://172.20.6.3/Problem_Show.asp?id=1518最开始只想到了n^2的写法,肯定要超时的,所以要对求gcd的过程进行优化.首先是前缀和容斥,很好理解.第二个优化大致如下:u为莫比乌斯函数,t为gcd(x,y)为i的倍数的数的个数:满足gcd(x,y)=1的数字对的数量=sigma(1<=i<=min(x,y))u[i]*t[i];t[i]=(x/i)*(y-i);由小数向下取整可知有连续的i满足x/i为定值,y/i也是定值,所以可以分块计算,用u[i]的前缀

HDU 6053 TrickGCD 莫比乌斯函数/容斥/筛法

题意:给出n个数$a[i]$,每个数可以变成不大于它的数,现问所有数的gcd大于1的方案数.其中$(n,a[i]<=1e5)$ 思路:鉴于a[i]不大,可以想到枚举gcd的值.考虑一个$gcd(a_1,a_2,a_3…a_n)=d$,显然每个$a_i$的倍数都满足,有$\frac{a_i}{d}$种方案 那么一个d对答案的贡献为\[\prod_{i=1}^{min(a)}{\lfloor\frac{a_i}{d}\rfloor}    \] 但是所有的d计入会有重复情况,考虑容斥,对d进行素数分

hdu1695(莫比乌斯)或欧拉函数+容斥

题意:求1-b和1-d之内各选一个数组成数对,问最大公约数为k的数对有多少个,数对是有序的.(b,d,k<=100000) 解法1: 这个可以简化成1-b/k 和1-d/k 的互质有序数对的个数.假设b=b/k,d=d/k,b<=d.欧拉函数可以算出1-b与1-b之内的互质对数,然后在b+1到d的数i,求每个i在1-b之间有多少互质的数.解法是容斥,getans函数参数的意义:1-tool中含有rem位置之后的i的质因子的数的个数. 在 for(int j=rem;j<=factor[i

HDU 5213 分块 容斥

给出n个数,给出m个询问,询问 区间[l,r] [u,v],在两个区间内分别取一个数,两个的和为k的对数数量. $k<=2*N$,$n <= 30000$ 发现可以容斥简化一个询问.一个询问的答案为 $[l,v]+(r,u)-[l,u)-(r,v]$,那么我们离线询问,将一个询问分成四个,分块暴力就行了. 然后就是注意细节,不要发生越界,访问错位置之类比较蠢的问题了. /** @Date : 2017-09-24 19:54:55 * @FileName: HDU 5213 分块 容斥.cpp

HDU 5072 Coprime (莫比乌斯反演+容斥+同色三角形)

Coprime Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 1469    Accepted Submission(s): 579 Problem Description There are n people standing in a line. Each of them has a unique id number. Now