您的位置:首页 > 其它

(暂时弃坑)(半成品)ACM数论之旅18---反演定理 第二回 Mobius反演(莫比乌斯反演)((づ ̄3 ̄)づ天才第一步,雀。。。。)

2016-02-23 17:46 453 查看
莫比乌斯反演也是反演定理的一种

既然我们已经学了二项式反演定理

那莫比乌斯反演定理与二项式反演定理一样,不求甚解,只求会用

莫比乌斯反演长下面这个样子(=・ω・=)

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 1e6 + 5;
int mu
, vis
, prime
;
int tot;//用来记录prime的个数
void init(){
mu[1] = 1;
for(int i = 2; i < N; i ++){
if(!vis[i]){
prime[tot ++] = i;
mu[i] = -1;
}
for(int j = 0; j < tot && i * prime[j] < N; j ++){
vis[i * prime[j]] = 1;
if(i % prime[j]) mu[i * prime[j]] = -mu[i];
else{
mu[i * prime[j]] = 0;
break;
}
}
}
}
LL Mobius(int a, int b){
LL ret = 0;
for(int i = 1; i <= a; i ++){//因为公式中有a/i,所以for到a就可以了
ret += 1ll * mu[i] * (a / i) * (b / i);
}
//我们现在求完了总对数,但是题目要求的类似(5,7)和(7,5)算一种
//所以接下来我们开始去重
LL temp = 0;
for(int i = 1; i <= a; i ++){
temp += 1ll * mu[i] * (a / i) * (a / i);
}
return ret - temp / 2;
//比如a=5,b=7那么(4,6)这样子的区间不可能有重复的(6,4)
//所以重复的部分只在1~a中,所以最后减去一半的重复区间就好了
}
int main(){
init();
int T, a, b, c, d, k;
scanf("%d", &T);
for(int cas = 1; cas <= T; cas ++){
scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
if(k == 0){
printf("Case %d: 0\n", cas);
continue;
}
b /= k; d /= k;
if(b > d) swap(b, d);
printf("Case %d: %I64d\n", cas, Mobius(b, d));
}
}


View Code

/////////////////此处施工中//////////////////

暂时弃坑。。。。
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=94200#overview
峰神挂的莫比乌斯反演章节,有兴趣自己去做做,不会的去百度。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: