ACM - 数学 - 提高(还没学多少)

news/2024/11/9 9:55:31/

ACM - 数学 练习题

  • 一、数论
    • 1、分解质因数 :AcWing 197. 阶乘分解
    • 2、求约数个数
      • (1)AcWing 1294. 樱花 (求 n!约数个数之和)
      • (2)AcWing 198. 反素数 (求 1 ~ N 中约数最多的数)
      • (3)AcWing 200. Hankson的趣味题(gcd * lcm == 两数之积)
    • 3、欧拉函数
      • (1)AcWing 201. 可见的点 :求有多少组互质的点
      • (2)AcWing 220. 最大公约数 :N内gcd为素数的数对数量
    • 4、同余
      • (1)AcWing 222. 青蛙的约会 :求一个未知数的同余方程
      • (2)AcWing 202. 最幸运的数字:至少x个连续的8能整除L
    • 5、

一、数论

1、分解质因数 :AcWing 197. 阶乘分解

原题链接:https://www.acwing.com/problem/content/199/
在这里插入图片描述

/*
先预处理素数,因为所有质因子只可能在素数集中。
再用 while ( n / 素数a ) 反求 n 中最多只能有多少个因子是 a。
*/
#include<iostream>using namespace std;const int N = 1000010;int primes[N], cnt = 0;
bool st[N];int ans[N];void init() {int n = N - 6;for (int i = 2; i <= n; ++ i) {if (!st[i]) primes[cnt ++] = i;for (int j = 0; primes[j] <= n / i; ++ j) {st[primes[j] * i] = true;if (i % primes[j] == 0) break;}}
}int main() {int n;cin >> n;init();//统计数量for (int i = 0; i < cnt; ++ i) {int j = n;while (j >= primes[i]) {ans[primes[i]] += j / primes[i];j /= primes[i];}}//输出答案for (int i = 2; i <= n; ++ i) {if (ans[i]) printf("%d %d\n", i, ans[i]);}if (n == 1) cout << "1 1" << endl;return 0;
}

2、求约数个数

(1)AcWing 1294. 樱花 (求 n!约数个数之和)

原题链接:https://www.acwing.com/problem/content/description/1296/

在这里插入图片描述
思路

因为 1 / x 和 1 / y 都小于 1 / n!,所以 x 和 y 都大于 n!。
在这里插入图片描述
故而在 x 是正整数的前提下,需要(x - n!)是 n!^ 2 的约数才可行。
而每一个(x - n!)中 x 只对应一个取值,相应的 y 也有唯一的取值。
所以题目就转换成 n!^ 2 有多少个约数。

借用分解质因数的做法,先预处理素数,因为所有质因子只可能在素数集中,再用 while ( n / 素数a ) 反求 n 中最多只能有多少个因子是 a,最后记得求模求解即可。

#include<iostream>using namespace std;const int N = 1000010, modd = 1e9 + 7;
#define ll long long//ans[j] 对应n!中有多少个素数j
ll ans[N], primes[N], cnt = 0;
bool st[N];//预处理素数
void init() {int n = N - 6;for (int i = 2; i <= n; ++ i) {if (!st[i]) primes[cnt ++] = i;for (int j = 0; primes[j] <= n / i; ++ j) {st[primes[j] * i] = true;if (i % primes[j] == 0) break;}}
}int main() {int n;cin >> n;init();//求个数for (int i = 0; i < cnt; ++ i) {int j = primes[i];if (j > n) break;int m = n;while (m > 0) {ans[j] += m / j;ans[j] %= modd;m /= j;}}//求结果ll res = 1;for (int i = 2; i <= n; ++ i) {if (ans[i]) {res *= (ans[i] * 2 + 1);res %= modd;}}cout << res;return 0;
}

(2)AcWing 198. 反素数 (求 1 ~ N 中约数最多的数)

原题链接:https://www.acwing.com/problem/content/200/
在这里插入图片描述
在这里插入图片描述

/*
由约数个数定理可知,约数个数只与指数有关,N 有上限的前提下,底数越小,指数的空间才越大。
所以可以从2, 3, 5, 7, 11, 13, 17, 19, 23, 29
(不用很多素数,因为单是这些数的一次方相乘就超过2e9)去爆搜。
由于要指数之积最大,所以指数的大小应当是单调不增的,这样才越慢接近N。
*/
#include<iostream>
using namespace std;#define ll long longll n, ans = 1, res = 1;
ll a[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
ll nums[15][40];
ll flag = 2e9;void dfs(int idx, int cnt, ll temp, ll num) {if (temp > ans || (temp == ans && num < res)) {ans = temp;res = num;}for (int i = cnt; i >= 0; -- i) {if (nums[idx][i] && num * nums[idx][i] <= n) {dfs(idx + 1, i, temp * (i + 1), num * nums[idx][i]);}}
}int main () {cin >> n;
// 	cout << 2L * 3 * 5 * 7 * 9 * 11 * 13 * 17 * 19 * 23  << endl;for (int i = 0; i <= 9; ++ i) {for (int j = 0; j <= 31; ++ j) {if (j == 0) nums[i][j] = 1;else {nums[i][j] = nums[i][j - 1] * a[i];}if (nums[i][j] > flag) break;}}dfs(0, 30, 1, 1);cout << res;
}

(3)AcWing 200. Hankson的趣味题(gcd * lcm == 两数之积)

原题链接:https://www.acwing.com/problem/content/description/202/

在这里插入图片描述
在这里插入图片描述

/*
由x和a0的最大公约数是a1,并不能获得x的上限。
但是x一定是b1的约数,而b1的约数最多只有1600个。
所以可以在获得b1所有质因子和次数后,dfs枚举b1的约数,逐一判断是否合法。或者按照下面代码的做法,获得b0的约数,假设该约数是gcd(x, b0),
由最大公约数*最小公倍数 == x * b0获得x的取值
*/
#include<iostream>
#include<vector>
#include<cmath>
#include<unordered_map>using namespace std;#define ll long longconst int N = 50000;ll n, a0, a1, b0, b1;
ll ans = 0;
int primes[N], cnt = 0;
bool st[N];//num-质因子 cnt-该质因子出现的次数
struct node{ll num, cnt;
};//初始化素数表
void init() {ll m = 50000;for (int i = 2; i <= m; ++ i) {if (!st[i]) primes[cnt ++] = i;for (int j = 0; primes[j] <= m / i; ++ j) {st[primes[j] * i] = true;if (i % primes[j] == 0) break;}}
}ll gcd(ll a, ll b) {return b == 0 ? a : gcd(b, a % b);
}//爆搜获得约数
void dfs(vector<node> v, int idx, ll num, unordered_map<ll, bool> book) {if (idx == v.size()) {ll x = num * b1 / b0;if (book.find(x) == book.end() && gcd(x, a0) == a1 && gcd(x, b0) == num && x * b0 == b1 * num) {++ ans;book[x] = true;}return;}for (int i = 0; i <= v[idx].cnt; ++ i) {dfs(v, idx + 1, num * pow(v[idx].num, i), book);}
}void solve() {vector<node> nums;unordered_map<ll, bool> book;ll b = b0;//获得质因子和次数for (int i = 0; i < cnt; ++ i) {ll c = 0;while (b % primes[i] == 0) {++ c;b /= primes[i];}if(c > 0) {nums.push_back({primes[i], c});}}if (b > 1) nums.push_back({b, 1});dfs(nums, 0, 1, book);
}int main () {cin >> n;init();while (n --) {cin >> a0 >> a1 >> b0 >> b1;ans = 0;solve();cout << ans << endl;}
}

3、欧拉函数

(1)AcWing 201. 可见的点 :求有多少组互质的点

原题链接:https://www.acwing.com/problem/content/203/
在这里插入图片描述
在这里插入图片描述

/*
本题抽象出来就是找所有第一象限过原点且斜率不同的直线有多少条。
设直线穿过点 x0、y0,由 y = kx 可得 k = y0 / x0。
假如 x0 和 y0 不互质,设他们存在大于 1 的公因数 d,那么点(x0 / d, y0 / d)也穿过该直线。
故而本题其实就是求解有多少组不同的(x,y)互质 ==》欧拉函数
*/
#include<iostream>using namespace std;const int N = 1010;int primes[N], cnt = 0;
int e[N];
bool st[N];void init() {int n = N - 5;e[1] = 1;for (int i = 2; i <= n; ++ i) {if (!st[i]) {primes[cnt ++] = i;e[i] = i - 1;}for (int j = 0; primes[j] <= n / i; ++ j) {st[primes[j] * i] = true;if (i % primes[j] == 0) {e[primes[j] * i] = primes[j] * e[i];break;}e[primes[j] * i] = e[i] * (primes[j] - 1);}}
}int main() {int t;cin >> t;init();for (int i = 1; i <= t; ++ i) {int n;cin >> n;int ans = 1;  for (int j = 1; j <= n; ++ j) ans += e[j] * 2; // 关于 y = x 对称cout << i << " " << n << " " << ans << endl;}
}

(2)AcWing 220. 最大公约数 :N内gcd为素数的数对数量

原题链接:https://www.acwing.com/problem/content/222/
在这里插入图片描述

/*
假设gcd(x, y) = d (d是素数),那么显然 gcd(x/d, y/d) = 1。
这意味着 x/d 和 y/d 是互质的。
据此,我们可以枚举 n 内的素数,求 n/d 范围所有能互质的对子的总数量。
受上一题(AcWing 201. 可见的点)的启发,我们可以预设 x/d <= y/d,先求对角线的一半,再翻倍即可。
res += 2 * sum[n / p] - 1; 是因为在乘2运算的时候对角线上的e[1]会被算两次,所以需要减1。
*/#include<iostream>using namespace std;const int N = 10000010;
#define ll long longint n;
int e[N],primes[N], cnt = 0;
bool st[N];
ll sum[N];  //欧拉函数的前缀和void init() {e[1] = 1;for (int i = 2; i <= n; ++ i) {if (!st[i]) {primes[cnt ++] = i;e[i] = i - 1;}for (int j = 0; primes[j] <= n / i; ++ j) {st[primes[j] * i] = true;if (i % primes[j] == 0) {e[primes[j] * i] = primes[j] * e[i];break;}e[primes[j] * i] = e[i] * (primes[j] - 1);}}for (int i = 1; i <= n; ++ i) sum[i] = sum[i - 1] + e[i];
}int main() {cin >> n;init();ll res = 0;for (int i = 0; i < cnt; ++ i) {int p = primes[i];res += 2 * sum[n / p] - 1;}cout << res;return 0;
}

4、同余

(1)AcWing 222. 青蛙的约会 :求一个未知数的同余方程

原题链接:https://www.acwing.com/problem/content/224/
在这里插入图片描述
在这里插入图片描述

/*
假设青蛙跳了 p 次,一共走了 q 个整圈,那么 p * (m - n) - q * l = y - x。
由于只有p、q是未知数,所以直接用exgcd求即可。
注意 d | (y - x) 才有解,而且最终跳的次数 p 需要乘上 (y - x) / d 才是方程的一组解。
最后再对 l / gcd 取模求最小整数解即可ac。
*/
#include<iostream>using namespace std;#define ll long longll exgcd(ll a, ll b, ll &x, ll &y) {if (b == 0) {x = 1;y = 0;return a;}ll d = exgcd(b, a % b, y, x);y -= a / b * x;return d;
}int main() {ll x, y, m, n, l, a, b;cin >> x >> y >> m >> n >> l;ll d = exgcd(m - n, l, a, b);if ((y - x) % d == 0) {a *= ((y - x) / d);ll u = abs(l / d);   //注意求绝对值cout << (a % u + u) % u << endl;}else cout << "Impossible";return 0;
}

(2)AcWing 202. 最幸运的数字:至少x个连续的8能整除L

原题链接:https://www.acwing.com/problem/content/description/204/
在这里插入图片描述
在这里插入图片描述

思路
在这里插入图片描述
① 使用欧拉定理时,10 和 c 互质的证明
把同余方程写成 10 ^ x + p * c = 1 的形式(p为未知数),假如 10 和 c 不互质,那么至少可以对等式左边提取出一个公因子 d,即: d * (10 ^ x / d + p * c / d)= 1.
很明显括号内的值不为0,当把 d 移到等式右边时,1 / d 不能整除且不能和左边相等,故而 d 必然为 1,即 10 和 c 一定互质。

② 同余方程的乘法法则
假如 a 同余 b(mod c),x 同余 y(mod c),那么 a * x 同余 b * y (mod c)。

= = = = =》

综上,我们可以发现先求出常数 c = 9 * L / gcd(L, 8),再求和 c 互质的数的个数 phi,再用快速幂check一遍phi的除数中能满足同余方程的最小的除数。

当然快速幂过程有10次方 * 10次方,所以需要在乘法过程中用一下龟速乘。

代码

//推导过程太过摧枯拉朽
#include<iostream>
#include<cmath>using namespace std;#define ll long longll l, phi, c;//求a和b的最大公约数
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;
}//求1~c中有多少个和c互质的数
ll eul(ll c) {ll res = c;ll len = sqrt(c);for (ll i = 2; i <= len; ++ i) {if (c % i == 0) {while (c % i == 0) {c /= i;}res /= i;res *= (i - 1);}}if (c != 1) {res /= c;res *= (c - 1);}return res;
}//龟速乘:求(a * b)% p
ll qmul(ll a, ll b, ll p) {ll res = 0, t = a;while (b) {if (b & 1) res = (res + t) % p;b >>= 1;t = (t + t) % p;}return res;
}//快速幂:求10的k次方mod c
ll qmi(ll a, ll k, ll p) {ll res = 1, t = a;while (k) {if (k & 1) res = qmul(res, t, p);k >>= 1;t = qmul(t, t, p);}return res == 1;
}//check(k):判断10的k次方模c是不是等于1,即判断k是不是一组解
bool check(ll k) {return qmi(10, k, c) == 1;
}int main() {int k = 1;while (cin >> l, l) {ll ans = 0x3f3f3f3f3f;c = 9 * l / gcd(l, 8);if (c % 2 == 0 || c % 5 == 0) ans = 0;phi = eul(c);for (ll i = 1; i <= phi / i; ++ i) {if (phi % i == 0) {if (check(i)) ans = min(ans, i);if (check(phi / i)) ans = min(ans, phi / i);}}printf("Case %d: %lld\n", k, ans);++ k;}return 0;
}

5、


http://www.ppmy.cn/news/66688.html

相关文章

使用RobustPCA 进行时间序列的异常检测

鲁棒主成分分析(Robust Principal Component Analysis, RobustPCA)是一种将时间序列矩阵分解为低秩分量和稀疏分量的技术。这种分解能够识别潜在的趋势&#xff0c;以及检测异常和异常值。在本中我们将研究RobustPCA的数学基础&#xff0c;介绍它与传统的PCA之间的区别&#xf…

算法题 — 寻找两数之和为目标值

文章目录 题目解法一解法二解法三总结 题目 给定一个数组和一个目标和&#xff0c;从数组中找两个数字相加等于目标和&#xff0c;输出这两个数字的下标。 解法一 直接循环两次求和比较是否和要求的目标值一致&#xff0c;一致的话打印出来 public int[] twoSum(int[] nums,…

面向对象【类的实例化与对象内存解析】

文章目录 类的概念对象的概念面向对象的三步骤对象的内存解析JVM 内存结构划分对象内存分析 类的概念 具有相同特征的事物的抽象描述&#xff0c;是抽象的、概念上的定义。 对象的概念 实际存在的该类事物的每个个体&#xff0c;是具体的&#xff0c;因而也称为实例。 面向…

顺序容器的使用方法

1)deque的使用 http://c.biancheng.net/cplus/ 学习网站 deque和vector都属于动态数组,不过deque比vector更加强大; #include #include #include using namespace std; int main() { deque a; a.push_back(3); a.push_front(4); a.push_back(3); a.push_front(4); a.insert(…

浅谈 Btrfs 文件系统的特点、优缺点以及使用场景

Btrfs&#xff08;B-Tree File System&#xff09;是一种先进的日志文件系统&#xff0c;最初由 Oracle 开发&#xff0c;现在已被广泛应用于 Linux 中。下面是 Btrfs 文件系统的特点、优缺点以及使用场景&#xff1a; 特点&#xff1a; Btrfs 文件系统支持快照、数据压缩、在…

14.构造器的排序分组.子查询

学习要点&#xff1a; 1.排序分组 2.子查询 本节课我们来开始学习数据库的构造器查询中的子查询、排序、分组等。 一&#xff0e;排序分组 1. 使用 whereColumn()方法实现两个字段相等的查询结果&#xff1b; //判断两个相等的字段&#xff0c;同样支持 orWhereColumn() //支持…

人人都可用的ChatGPT,Edge浏览器-免费ChatGPT保姆级教程!非常详细!

人工智能大浪潮已经来临&#xff0c;对于ChatGPT&#xff0c;我觉得任何一个玩互联网的人&#xff0c;都应该重视起来&#xff0c;用起来。但是国内使用需要解决科学上网、注册、收费等繁琐问题。 所以&#xff0c;今天这篇文章就来推荐一个插件&#xff0c;无需任何繁琐操作&…

收集的面试题链接

目录 一份非常值得一看的Java面试题Java面试笔试题大汇总一(最全详细答案)Java面试题大全&#xff08;2020版&#xff09;JAVA面试题集模板.doc 一份非常值得一看的Java面试题 https://www.cnblogs.com/bailing80/p/11443409.html Java面试笔试题大汇总一(最全详细答案) 汇总…