HDU 6053 TrickGCD 莫比乌斯反演||筛法
来源:互联网 发布:产品经理流程图软件 编辑:程序博客网 时间:2024/06/05 02:02
传送门:HDU6053
题意:给定一个序列Ai,构造一个序列Bi,满足Bi<=Ai并且gcd(Bi)>=2. 问有多少种Bi序列
正解:比赛的时候有点容斥的思路,但是感觉容斥太麻烦了,就换了题去搞,完全忘了莫比乌斯反演。。
显然我们要枚举gcd,然后对于每个gcd求所有(Ai/gcd)的乘积,最后再加起来,但是这个过程会有重复的,
需要容斥,用莫比乌斯函数即可,好像也有用类似于筛法一样的容斥也能过。
搜的网上题解大多数用莫比乌斯函数的都是在函数前面加一个负号,我不是太懂为什么,但是自己举了几个小例子也是满足这个负号的,后来看到一篇博客是直接套用的书上给的莫比乌斯反演公式:
定义f[n]表示n是最大公约数情况下的计数,F[n]为n是公约数情况下的计数。
这样∑f[i](2<=i<=min(a[i]))就是要求的结果。
这样我写就明白多了嘛。。但还是希望能有大佬给解释一下为什么直接-μ(n)*F[n]也是可以的。
本题的难点还有一个就是如何快速求得(Ai/gcd)的乘积,我们可以维护一个前缀和数组b[],b[i]表示有多少Ai<=i,
然后我们类似筛法一样的枚举,假设当前枚举的gcd为d,那么j * d - 1 到 (j + 1) * d - 1 除以d的商都是j,结合b[]数组
我们就可以快速求出除以d商为j的Ai有几个了,这样复杂度和筛法差不多,nlogn数量级。
我看网上很多dalao用纯筛法的思路进行计数和容斥,也是很强的思路。
最后就是这是第一次写求莫比乌斯函数的代码,根据书上的定义写了很长,结果看网上大佬3行就解决了。。
代码:
#include<bits/stdc++.h>#define ll long long#define pb push_back#define fi first#define se second#define pi acos(-1)#define inf 0x3f3f3f3f#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define rep(i,x,n) for(int i=x;i<n;i++)#define per(i,n,x) for(int i=n;i>=x;i--)using namespace std;const int mod = 1e9 + 7;typedef pair<int,int>P;const int MAXN=100010;int gcd(int a,int b){return b?gcd(b,a%b):a;}int f[MAXN];//f为moebius函数值 ll F[MAXN];/*void mobius(ll mn) //大佬代码,mu[]即为moebius值 { mu[1]=1; for(ll i=1;i<=mn;i++){ for(ll j=i+i;j<=mn;j+=i){ mu[j]-=mu[i]; } } } */void moebius(){ f[1] = 1; for(int i = 2; i < MAXN; i++) { if(f[i] == 0) { for(int j = i; j < MAXN; j += i) f[j]++; } } for(int i = 2; i < MAXN; i++) if(f[i] & 1) f[i] = -1; else f[i] = 1; for(int i = 2; i * i < MAXN; i++) { for(int j = i * i; j < MAXN; j += i * i) f[j] = 0; }}int a[MAXN];int b[MAXN * 2];//前缀和数组 ll qmul(int a, int b){ ll ans = 1, t = a; while(b) { if(b & 1) ans *= t; t *= t; b >>= 1; ans %= mod; t %= mod; } return ans;}int main(){ int T; moebius(); //for(int i = 1; i <= 20; i++) //cout << f[i] <<" "; cin >> T; for(int kase = 1; kase <= T; kase++) { int n; scanf("%d", &n); memset(b, 0, sizeof(b)); for(int i = 0; i < n; i++) scanf("%d", a + i), b[a[i]]++; for(int i = 0; i < 2 * MAXN; i++) b[i] += b[i - 1]; int up = *min_element(a, a + n); ll ans = 0; for(int i = 2; i <= up; i++)//枚举gcd { ll num = 1; for(int j = 1; j * i <= MAXN; j++) { num *= qmul(j, b[(j + 1) * i - 1] - b[j * i - 1]); num %= mod; } F[i] = num; //ans -= f[i] * num; //ans = (ans % mod + mod) % mod; } for(int i = 2; i <= up; i++) { ll num = 1; for(int j = 1; j * i <= MAXN; j++) ans += f[j] * F[i * j], ans %= mod; //ans -= f[i] * num; //ans = (ans % mod + mod) % mod; //cout << ans << endl; } printf("Case #%d: %lld\n", kase, ans); } return 0;}
定理:和是定义在非负整数集合上的两个函数,并且满足条件,那么我们得到结论
另一种描述:
在上面的公式中有一个函数,它的定义如下:
(1)若,那么
(2)若,均为互异素数,那么
(3)其它情况下
对于函数,它有如下的常见性质:
(1)对任意正整数有
(2)对任意正整数有
转载自:点击打开链接
- HDU 6053 TrickGCD 莫比乌斯反演||筛法
- HDU 6053 TrickGCD(莫比乌斯反演+分块)
- 【HDU 6053 TrickGCD】 + 莫比乌斯反演
- HDU 6053 TrickGCD(莫比乌斯反演)
- hdu 6053 TrickGCD(莫比乌斯反演)
- HDU 6053 TrickGCD(莫比乌斯反演+前缀和)
- HDU 6053 TrickGCD(莫比乌斯反演)
- hdu6053 TrickGCD 莫比乌斯反演
- HDU 6053 TrickGCD (桶装+分段 / 莫比乌斯反演)
- 2017多校第二场 HDU 6053 TrickGCD 莫比乌斯反演
- TrickGCD(HDU 6053 莫比乌斯函数的反演)
- hdu 6053 TrickGCD 【容斥&筛法|莫比乌斯】
- 2017多校训练赛第二场 HDU 6053 TrickGCD(容斥原理/莫比乌斯反演)
- 解题报告:HDU_6053 TrickGCD 莫比乌斯反演
- HDU6053-TrickGCD 容斥原理+莫比乌斯反演
- hdu 6053 TrickGCD [莫比乌斯函数]
- Hdu-6053 TrickGCD(莫比乌斯函数)
- hdu 6053 TrickGCD 容斥 莫比乌斯
- 小e开发板(esp8266)连接Arduino实现WiFi扫描
- 1.7 HashMap源码分析
- 将SqlServer表转换为Markdown
- LeetCode 9. Palindrome Number
- C
- HDU 6053 TrickGCD 莫比乌斯反演||筛法
- linux绑定双网卡配置及各模式数据流量传输方式
- Leetcode 644. Maximum Average Subarray II 最大平均区间2 解题报告
- 关键字
- Ceres-Solver学习笔记(6)
- R语言粒子群优化算法
- Jump Game问题及解法
- layer回调函数
- 面向对象的程序设计之工厂模式