整理的算法模板合集: ACM模板


目录

  • 一、约数个数
    • 1. AcWing 1291. 轻拍牛头
    • 2. AcWing 1294. 樱花
    • 2.1 AcWing 197. 阶乘分解
    • 3. AcWing 198. 反素数
    • 4. AcWing 200. Hankson的趣味题
  • 二、欧拉函数
    • 1. AcWing 201. 可见的点
    • 2. AcWing 220. 最大公约数
题目 算法
AcWing 1291. 轻拍牛头 求约数的个数
AcWing 1294. 樱花 求(n!)2(n!)^2(n!)2的约数的个数
AcWing 198. 反素数 通过分析元素性质发现可以直接dfs

一、约数个数

本节前半部分需要用到的知识:

由算数基本定理得正整数N可以写作N=p1C1×p2C2×p3C3⋯×pmCmN=p_1^{C_1}\times p_2^{C_2} \times p_3^{C_3} \cdots \times p_m^{C_m}N=p1C1​​×p2C2​​×p3C3​​⋯×pmCm​​

N的正约数个数为(ΠΠΠ是连乘积的符号,类似∑∑∑)

(c1+1)×(c2+1)×⋯(cm+1)=Πi=1m(ci+1)(c_1+1)\times (c_2+1)\times \cdots (c_m+1)=\Pi_{i=1}^{m}(ci+1)(c1​+1)×(c2​+1)×⋯(cm​+1)=Πi=1m​(ci+1)
N的所有正约数和为

(1+p1+p12+⋯+p1c1)×⋯×(1+pm+pm2+⋯+pmcm)=∏i=1m(∑j=0ci(pi)j)(1+p_1+p_1^2+\cdots +p_1^{c_1})\times\cdots\times(1+p_m+p_m^2+\cdots +p_m^{c_m})=\prod_{i=1}^{m}(\sum_{j=0}^{c_i}(p_i)^j)(1+p1​+p12​+⋯+p1c1​​)×⋯×(1+pm​+pm2​+⋯+pmcm​​)=i=1∏m​(j=0∑ci​​(pi​)j)

1. AcWing 1291. 轻拍牛头


因为
如果我们分别求每个数的约数的个数,那么每次的时间复杂度至少是O(n)O(\sqrt n)O(n​)的,所以我们没必要每次都一个一个求,我们正着直接求很难,那么我们就倒着求,我们类比线性筛的思路,如果对于一个数x而言,数d是x的约数,那么x一定是d的倍数,所以我们直接筛一遍倍数即可。时间复杂度为O(nlogn)O(nlogn)O(nlogn)

注意最后需要除去自己

#include<cstdio>
#include<algorithm>
#include<cstring>using namespace std;const int N = 1000007;int n, m;
int a[N];
int primes[N];
int cnt[N];
int S[N];int main()
{scanf("%d", &n);for(int i = 1; i <= n; ++ i){scanf("%d", &a[i]);cnt[a[i]] ++ ;}for(int i = 1; i <= 1e6; ++ i){//nlognfor(int j = i; j <= 1e6; j += i){S[j] += cnt[i];}}for(int i = 1; i <= n; ++ i)printf("%d\n", S[a[i]] - 1);//除去它自己return 0;
}

2. AcWing 1294. 樱花



所以本题实际上转换成了求n!2n!^2n!2的约数的个数,我们根据公式,

由算数基本定理得正整数N可以写作N=p1C1×p2C2×p3C3⋯×pmCmN=p_1^{C_1}\times p_2^{C_2} \times p_3^{C_3} \cdots \times p_m^{C_m}N=p1C1​​×p2C2​​×p3C3​​⋯×pmCm​​

N的正约数个数为(ΠΠΠ是连乘积的符号,类似∑∑∑)

(c1+1)×(c2+1)×⋯(cm+1)=Πi=1m(ci+1)(c_1+1)\times (c_2+1)\times \cdots (c_m+1)=\Pi_{i=1}^{m}(ci+1)(c1​+1)×(c2​+1)×⋯(cm​+1)=Πi=1m​(ci+1)

求一个数的约数个数是分解质因数连乘,那么求一个数的阶乘的约数的个数实际上就是求1~n的每个数的约数个数的乘积。

因为n!2n!^2n!2太大了,所以我们引入一道题目:我们发现只需要将阶乘分解之后,所有质因子的指数的乘积的二倍既是答案。

2.1 AcWing 197. 阶乘分解


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 1000010;int primes[N], cnt;
bool st[N];void init(int n)
{for (int i = 2; i <= n; i ++ ){if (!st[i]) primes[cnt ++ ] = i;for (int j = 0; primes[j] * i <= n; j ++ ){st[i * primes[j]] = true;if (i % primes[j] == 0) break;}}
}int main()
{int n;cin >> n;init(n);for (int i = 0; i < cnt; i ++ ){int p = primes[i];int s = 0;for (int j = n; j; j /= p) s += j / p;printf("%d %d\n", p, s);}return 0;
}

所以我们只需要在上述代码中稍作修改,累积的是每个质因子的指数的二倍即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>using namespace std;const int N = 1000007;
typedef long long ll;
ll mod = 1e9 + 7;ll n, m, cnt;
int primes[N];
bool vis[N];void get_primes(ll n)
{vis[0] = vis[1] = 1;for(int i = 2; i <= n; ++ i){if(vis[i] == 0){primes[++ cnt] = i;}for(int j = 1; j <= cnt && i * primes[j] <= n; ++ j){vis[i * primes[j]] = true;if(i % primes[j] == 0)break;}}
}int main(){scanf("%lld", &n);get_primes(n);ll res = 1;for(int i = 1; i <= cnt; ++ i){int p = primes[i];int sum = 0;for(int j = n; j; j /= p)sum += j / p;res = (res * (2 * sum + 1)) % mod;}cout << res % mod << endl;return 0;
}

3. AcWing 198. 反素数

很重要的一个解决问题的方法:找题目的性质!!!

如果没有思路的话,或者说数论的题目,所给的条件太少了,我们可以找一下题目中各各变量的性质!


所以我们直接爆搜即可。然后搜的过程中应用那三个我们发现的性质,其中这三个性质在之后的题目中用处也是非常大的。

//我们只用到了最多9个质因子,因为再多乘起来就大于1e9了,所以我们直接打表找到前9个质因子即可。
//我们需要找到的是约数个数最多的最小的数
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>using namespace std;const int N = 500007;
typedef long long ll;
int primes[9] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
int n, m;
int maxnum, number;
//使用的是第几个质数,最大次数,乘起来得到的x(反素数备选项),当前约数的个数(我们要找的是约数个数最多的最小的数)
void dfs(int cnt, int last_pow, int mul, int num)
{if(num > maxnum || (num == maxnum &&  mul < number)){maxnum = num;number = mul;}if(cnt == 9)return ;for(int i = 1; i <= last_pow; ++ i){//当前质因子的次数if((ll)primes[cnt] * mul > n) break;mul *= primes[cnt];//这个是要修改的dfs(cnt + 1, i, mul, num * (i + 1));//约数个数就是Π(ci + 1)}
}int main()
{scanf("%d", &n);dfs(0, 30, 1, 1);cout << number << endl;return 0;
}

4. AcWing 200. Hankson的趣味题

我的标程(能过原题):
但是y总竟然造了一组数据把标程给卡T了…

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>using namespace std;const int N = 50007;
int n, m, t, ans;
int a, b, c, d;int read()
{int x = 0, f = 1;char ch = getchar();while(ch > '9' || ch < '0'){if(ch == '-')f = -1; ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}return x * f;
}int gcd(int a, int b)
{if(b == 0)return a;return gcd(b, a % b);
}int main()
{t = read();while(t -- ){ans = 0;a = read(), b = read(), c = read(), d = read();for(int x = 1, y; x * x <= d; ++ x){if(d % x == 0){if(gcd(x, a) == b && d * gcd(x, c) == x * c){ans ++ ;}if(x != d / x){y = d / x;if(gcd(y, a) == b && d * gcd(y, c) == y * c){ans ++ ;}}}}printf("%d\n", ans);}return 0;
}


%%%

#include <iostream>
#include <algorithm>
#include <vector>using namespace std;typedef long long LL;
typedef pair<int, int> PII;const int N = 45000, M = 50;int primes[N], cnt;
bool st[N];PII factor[M];
int cntf;int divider[N], cntd;void get_primes(int n)
{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 gcd(int a, int b)
{return b ? gcd(b, a % b) : a;
}void dfs(int u, int p)
{if (u > cntf){divider[cntd ++ ] = p;return;}for (int i = 0; i <= factor[u].second; i ++ ){dfs(u + 1, p);p *= factor[u].first;}
}int main()
{get_primes(N);int n;scanf("%d", &n);while (n -- ){int a0, a1, b0, b1;scanf("%d%d%d%d", &a0, &a1, &b0, &b1);int d = b1;cntf = 0;for (int i = 0; primes[i] <= d / primes[i]; i ++ ){int p = primes[i];if (d % p == 0){int s = 0;while (d % p == 0) s ++, d /= p;factor[ ++ cntf] = {p, s};}}if (d > 1) factor[ ++ cntf] = {d, 1};cntd = 0;dfs(1, 1);int res = 0;for (int i = 0; i < cntd; i ++ ){int x = divider[i];if (gcd(x, a0) == a1 && (LL)x * b0 / gcd(x, b0) == b1){res ++ ;}}printf("%d\n", res);}return 0;
}

二、欧拉函数


线性筛筛欧拉函数的原理

1. AcWing 201. 可见的点



用线性筛筛欧拉函数即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<iostream>using namespace std;
typedef long long ll;
const int N = 500007, M = 1000007, INF = 0x3f3f3f3f;
const double inf = 1e100;
const double eps = 1e-8;
const int mod = 10007;int primes[N], cnt;
int phi[N];
bool vis[N];void init(int n)
{phi[1] = 1;for(int i = 2; i <= n; ++ i){if(!vis[i]){primes[ ++ cnt] = i;phi[i] = i - 1;}for(int j = 1; j <= cnt && i * primes[j] <= n; ++ j){vis[i * primes[j]] = true;if(i % primes[j] == 0){//最小的质因子phi[i * primes[j]] = phi[i] * primes[j];break;}else phi[i *primes[j]] = phi[i] * (primes[j] - 1);}}}int n, m, t, kcase;int main()
{scanf("%d", &t);init(N - 1);while(t -- ){scanf("%d", &n);ll ans = 0;for(int i = 1; i <= n; ++ i)ans += phi[i] * 2;printf("%d %d %lld\n",  ++ kcase, n, ans + 1);}return 0;
}

2. AcWing 220. 最大公约数


我们可以莫比乌斯反演!

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>using namespace std;
typedef long long ll;
const int N = 10000007;int n, m;
int primes[N];
int phi[N];
int cnt;
bool vis[N];
ll sum[N];void init(int n)
{phi[1] = 0;//这里应该是0for(int i = 2; i <= n; ++ i){if(vis[i] == 0){primes[ ++ cnt] = i;phi[i] = i - 1;}for(int j = 1; j <= cnt && primes[j] * i <= n; ++ j){vis[i * primes[j]] = true;if(i % primes[j] == 0){phi[i * primes[j]] = phi[i] * primes[j];break;}phi[i * primes[j]] = phi[i] * (primes[j] - 1);}}for(int i = 1; i <= n; ++ i)//求phi[n]的前缀和sum[i] = sum[i - 1] + phi[i];
}int main()
{scanf("%d", &n);init(n);ll ans = 0;for(int i = 1; i <= cnt; ++ i){int p = primes[i];ans += sum[n / p] * 2 + 1;}printf("%lld\n", ans);return 0;
}
  • P2398 GCD SUM
  • P4139 上帝与集合的正确用法

【数学专题】约数个数与欧拉函数相关推荐

  1. 1~n中与n互质数的个数(欧拉函数)

    对于1~n中所有跟n互质的数的个数问题,我们会用欧拉函数来解决. 在开始讲欧拉函数之前,需要先了解质因数分解,传送门:http://t.csdn.cn/tqzvO.ok现在正式开始欧拉函数的推导. 以 ...

  2. 互质数的个数(欧拉函数)C/C++

    欧拉函数 O(n)=n(1-1/P1)(1-1/P2)-(1-1/Pn) ,其中P1-Pn为n的质因子,求出来的结果就是题目所求. 不知道为社么这么写时间超限,下面那种方式写就能过. #include ...

  3. 【数论】【Polya定理】【枚举约数】【欧拉函数】【Java】poj2154 Color

    你随便写一下出来,发现polya原理的式子里面好多gcd是相同的,gcd(n,i)=k可以改写成gcd(n/k,i/k)=1,也就是说指数为k的项的个数为phi(n/k),就很好求了,最后除的那个n直 ...

  4. 数学/数论专题:莫比乌斯函数与欧拉函数

    数学/数论专题:莫比乌斯函数与欧拉函数(进阶) 0. 前言 1. 前置知识 2. 正文 3. 总结 4. 参考资料 0. 前言 本篇文章会从狄利克雷卷积的角度,讨论莫比乌斯函数与欧拉函数的相关性质. ...

  5. 数学知识——欧拉函数

    1. 欧拉函数 定义:欧拉函数ψ(n) 表示1~n中与n互质的数的个数 公式:如果一个数可以被分解质因式为N = p1α1 *p2α2--pkαk 则ψ(n) = n(1 - 1/p1)(1 - 1/ ...

  6. 欧拉函数——数学知识(c++)

    定义:欧拉函数表示1-N中与N互质的数的个数: 给定一个数n,求在[1,n]这个范围内两两互质的数的个数 对于这个范围内的每一个数,我们只要找到不超过这个数且与这个数互质的数的个数就可以了 欧拉函数用 ...

  7. 数论 —— 欧拉函数

    [定义] 对正整数 n,欧拉函数是小于等于 n 的数中与 n 互质的数的个数,记作: 例如:,因为 1.3.5.7 均与 8 互质. [性质] 1)若 n 为一素数 p,则: 2)若 n 为一素数 p ...

  8. 算法 {欧拉函数,欧拉定理,费马小定理}

    欧拉函数 定义 ϕ ( x ) , x ∈ N + \phi(x), \ \ x \in N^+ ϕ(x),  x∈N+ means the number of y ∈ N + y \in N^+ y ...

  9. 费马定理中值定理_数论-欧拉函数、欧拉定理

    欧拉函数 积性函数 满足 ( 互质) 定义 对于正整数 ,欧拉函数是小于等于 的所有数中与 互质的数的 个数. 欧拉函数是积性函数(这个证明不是很显然,这个链接里面有很多种证明方法) 记作: 公式 , ...

最新文章

  1. 用计算机解组合题,计算机组成原理试题解析5
  2. 如何利用PyTorch中的Moco-V2减少计算约束
  3. 演讲实录丨王海峰:AI 新基建加速产业智能化
  4. windows7升级安装之初体验
  5. 全球大半网络瘫痪,背后原因竟来自这家无名小公司
  6. Zookeeper服务端线程分析(单机)
  7. python程序填空程序改错_Python - class dummyclass(object): 改错
  8. no python interpreter configured
  9. curl循环监控_阿里巴巴开源性能监控神器Arthas
  10. H3C FTP配置示例
  11. 如何在IE让用户自动下载ActiveX控件?
  12. 在android studio中如何创建一个类来继承另外一个类_在Android使用Transition API检测用户活动...
  13. 攻城狮算保险--理财型,还是消费型?
  14. 图灵接口 php,图灵机器人API接口
  15. 从NVIDIA官方网站上下载CUDA的方法
  16. 【Anki 牌组+Markdown笔记分享】汇编语言
  17. 3D大型网络游戏腐竹制作教程
  18. SciTE 编辑器汉化
  19. imtoken官网通告SHIB拥有自己的Shibarium区块链,
  20. centOS7安装 mysql-community-release-el7-5.noarch.rpm 包

热门文章

  1. 毕业BG(01背包问题)
  2. CentOS7图形界面与命令行界面切换
  3. Redis 数据结构-字典源码分析
  4. Java学习提升体系结构
  5. 实战centos6安装zabbix-2.4版(终极版)
  6. Javascript正则匹配不含某子串
  7. openstack网络服务neutron
  8. 碰到故障大全---cd
  9. iptables踩坑记
  10. IOS、java支持DES加密