HDU 1695 GCD 容斥原理/莫比乌斯反演

2024-06-12 11:38

本文主要是介绍HDU 1695 GCD 容斥原理/莫比乌斯反演,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题意:

给你两个区间[a,b],[c,d],还有一个k。让你从区间[a,b]中找出x,[c,d]中找出y,问共有多少组(x,y)使得gcd(x,y)=k。

(x,y)和(y,x)算一组。

思路:

参考:http://blog.csdn.net/yang_7_46/article/details/9072533

容斥。


普通容斥:

*如果gcd(x,y)=k,则gcd(x/k,y/k)=1。那么对于两个区间来说,我们都默认进行了b = b/k,d = d/k操作。(a,c固定为1)。(这样做并不会使得组数遗漏)

因为(x,y)和(y,x)只算一组,因此在容斥过程中,我们要保证x < y,这样才不会重复计算。

剩下就是容斥的过程,可以戳这里。

其它一些细节要自己处理一下,例如b = 1或者d = 1的时候。


莫比乌斯反演:

莫比乌斯资料:http://blog.csdn.net/acdreamers/article/details/8542292

定义f(n):gcd(x, y)为n的方案数。

定义F(n):gcd(x, y)是n的倍数的方案数。

则我们要求的就是f(1)。默认b < d,并且都已经除以k。

F(n) = (b/n)*(d/n);

套用莫比乌斯公式即可。


code(普通容斥):

#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;const int MAXN = 1e5+5;
typedef long long LL;int a, b, c, d, k;
bool isp[MAXN+5];
vector <int> vec[MAXN+5];void prime()
{memset(isp, false, sizeof(isp));for(int i = 2;i <= MAXN; i++){if(!isp[i]){vec[i].push_back(i);for(int j = i*2; j <= MAXN; j += i){isp[j] = true;vec[j].push_back(i);}}}
}
LL calc(int t, int p)
{LL ret, v = 1;int cnt = 0;for(int i = 0;i < vec[t].size(); i++){if((1<<i)&p){cnt++;v *= vec[t][i];}}if(v == 0) return 0;ret = (LL)(d-t)/v;if(cnt%2 == 0) ret = -ret;return ret;
}void solve()
{//tepan 1LL res = d;for(int i = 2;i <= b; i++){res += d-i;for(int j = 1;j < (1<<vec[i].size()); j++)res -= calc(i, j);}printf("%I64d\n", res);
}int main()
{prime();int T, cas = 0;scanf("%d", &T);while(T--){scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);printf("Case %d: ", ++cas);if(k == 0){puts("0");continue;}b /= k, d /= k;if(b > d) swap(b, d);if(b == 0 || d == 0)puts("0");else solve();}return 0;
}

 code(莫比乌斯反演):

#include <bits/stdc++.h>
using namespace std;const int N = 1e5+5;
typedef long long LL;int b, d, k;
int prime[N], cnt;
int mu[N];
bool vis[N];
void Mobius() {mu[1] = 1;cnt = 0;for(int i = 2;i < N; i++) {if(!vis[i]) {mu[i] = -1;prime[cnt++] = i;}for(int j = 0;j < cnt; j++) {if(i*prime[j] >= N) break;vis[i*prime[j]] = true;if(i%prime[j] != 0)mu[i*prime[j]] = -mu[i];else {mu[i*prime[j]] = 0;break;}}}
}int main() {Mobius();int T, cas = 0;scanf("%d", &T);while(T--) {scanf("%*d%d%*d%d%d", &b, &d, &k);printf("Case %d: ", ++cas);if(k == 0) {puts("0");continue;}b /= k, d /= k;if(b > d) swap(b, d);LL ans = 0;for(int i = 1;i <= b; i++)ans += 1ll*mu[i]*(b/i)*(d/i);LL tmp = 0;for(int i = 1;i <= b; i++)tmp += 1ll*mu[i]*(b/i)*(b/i);printf("%I64d\n", ans-tmp/2);}return 0;
}



这篇关于HDU 1695 GCD 容斥原理/莫比乌斯反演的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1054115

相关文章

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

hdu 3790 (单源最短路dijkstra)

题意: 每条边都有长度d 和花费p,给你起点s 终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。 解析: 考察对dijkstra的理解。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstrin

hdu 2489 (dfs枚举 + prim)

题意: 对于一棵顶点和边都有权值的树,使用下面的等式来计算Ratio 给定一个n 个顶点的完全图及它所有顶点和边的权值,找到一个该图含有m 个顶点的子图,并且让这个子图的Ratio 值在所有m 个顶点的树中最小。 解析: 因为数据量不大,先用dfs枚举搭配出m个子节点,算出点和,然后套个prim算出边和,每次比较大小即可。 dfs没有写好,A的老泪纵横。 错在把index在d