求出一个数的所有约数
#include<iostream>
#include<vector>
using namespace std;
vector<int> v;
int main()
{
int n;
cin>>n;
// 求出n的所有约数
for(int i=1;i*i<=n;i++){
if(n%i==0){
v.push_back(i);
if(n/i!=i) v.push_back(n/i);
}
}
// 遍历n的所有约数
for(auto i = v.begin();i!=v.end();i++) cout<<(*i)<<' ';
return 0;
}
判定法求质数(素数)
模板:
//试除法
bool is_prime(int x)
{
if (x < 2) return false;//最小的质数是2
//以12为例,当i=2时,i<=6,当i=3时,i<=4,当i=4时,i<=3退出for循环
//12=2*6,只要判断12/2即可判定其为合数,无需再进行下面的判断
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
return false;
return true;
}
//acwing
例题
给定 n 个正整数 ai,判定每个数是否是质数。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含一个正整数 ai。
输出格式
共 n 行,其中第 i 行输出第 i 个正整数 ai 是否为质数,是则输出 Yes,否则输出 No。
数据范围
1≤n≤100,
1≤ai≤231−1
输入样例:
2
2
6
输出样例:
Yes
No
#include <iostream>
#include <algorithm>
using namespace std;
bool is_prime(int x)
{
if (x < 2) return false;
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
return false;
return true;
}
int main()
{
int n;
cin >> n;
while (n -- )
{
int x;
cin >> x;
if (is_prime(x)) puts("Yes");
else puts("No");
}
return 0;
}
分解质因数
质因数就是一个数的约数
,并且是质数
。
质数又称素数,正因数只有1和它本身
1既不是质数也不是合数
模板
//试除法
void divide(int x)
{
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
{
int s = 0;
while (x % i == 0) x /= i, s ++ ;//相同的因数可以不止有一个
//比如8=2*2*2
cout << i << ' ' << s << endl;
}
if (x > 1) cout << x << ' ' << 1 << endl;//质数情况,此时若x>1说明x是质数
cout << endl;
}
//acwing
例题
给定 n 个正整数 ai,将每个数分解质因数,并按照质因数从小到大的顺序输出每个质因数的底数和指数。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含一个正整数 ai。
输出格式
对于每个正整数 ai,按照从小到大的顺序输出其分解质因数后,每个质因数的底数和指数,每个底数和指数占一行。
每个正整数的质因数全部输出完毕后,输出一个空行。
数据范围
1≤n≤100,
2≤ai≤2×109
输入样例:
2
6
8
输出样例:
2 1
3 1
2 3
#include <iostream>
#include <algorithm>
using namespace std;
void divide(int x)
{
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
{
int s = 0;
while (x % i == 0) x /= i, s ++ ;
cout << i << ' ' << s << endl;
}
if (x > 1) cout << x << ' ' << 1 << endl;
cout << endl;
}
int main()
{
int n;
cin >> n;
while (n -- )
{
int x;
cin >> x;
divide(x);
}
return 0;
}
筛质数
模板
//线性筛法求素数
int primes[N], cnt; // primes[]存储所有素数
bool st[N]; // st[x]存储x是否被筛掉
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;
}
}
}
//acwing
线性筛法核心:
每个合数是被其最小的质因数给筛掉的
每个被筛掉的合数,只被筛掉一次,而不是多次
因为6%2==0
说明6能继续拆分成2 * 3,如果要是以3 * 6来筛掉18时就不满足最小质数来筛除的条件了
因为18应该由2*9筛掉,而不是3 * 6,所以此时要break
例题
给定一个正整数 n,请你求出 1∼n 中质数的个数。
输入格式
共一行,包含整数 n。
输出格式
共一行,包含一个整数,表示 1∼n 中质数的个数。
数据范围
1≤n≤106
输入样例:
8
输出样例:
4
#include<iostream>
using namespace std;
const int N=1000010;
int primes[N],cnt;//primes存放当前已经筛选出来的质数
bool st[N];//存放是否被筛选掉
int fun(int n){
for(int i=2;i<=n;i++){//质数从2开始
if(!st[i]){//如果没有被筛掉说明是质数
primes[cnt++]=i;//将质数保存在primes数组
}
for(int j=0;primes[j]<=n/i;j++){//减少for循环的次数,如果是j<=cnt,会造成primes[j]*i>n且会多执行几次
st[primes[j]*i]=true;//用当前最小的质因数来筛掉合数
//如6=2*3,6被2筛掉,而不是被3筛掉
//i%primes[j] ==0说明i能分解成质因数*的形式
//如4能分解成2*2,这时就不用用4筛某个数,而是2
if(i%primes[j] ==0) break;
}
}
return cnt;
}
int main()
{
int n;
cin>>n;
cout<<fun(n);
return 0;
}
最大公约数
模板
//欧几里得算法
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
//acwing
例题
给定 n 对正整数 ai,bi,请你求出每对数的最大公约数。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含一个整数对 ai,bi。
输出格式
输出共 n 行,每行输出一个整数对的最大公约数。
数据范围
1≤n≤105,
1≤ai,bi≤2×109
输入样例:
2
3 6
4 6
输出样例:
3
2
#include<iostream>
#include<cmath>
using namespace std;
//欧几里得算法总结:
//1.大数除以小数
//2.上一个算式的除数作为当前算式的被除数,余数作为除数
//3.重复上述步骤,直至余数为0时的除数为最大公约数
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
int a,b;
cin>>a>>b;
cout<<gcd(max(a,b),min(a,b))<<endl;
}
return 0;
}
求组合数
模板
递归法求组合数
// c[a][b] 表示从a个苹果中选b个的方案数
for (int i = 0; i < N; i ++ )
for (int j = 0; j <= i; j ++ )
if (!j) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;//公式
//acwing
例题:
给定 n 组询问,每组询问给定两个整数 a,b,请你输出 Cbamod(10的9次方+7) 的值。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含一组 a 和 b。
输出格式
共 n 行,每行输出一个询问的解。
数据范围
1≤n≤10000,
1≤b≤a≤2000
输入样例:
3
3 1
5 3
2 2
输出样例:
3
10
1
#include<iostream>
using namespace std;
const int N=2010,mod=1e9+7;
int c[N][N];
void init()
{
//c[a][b]表示从a个苹果中选b个的方案数
//先进行预处理
//预处理过后直接用即可
for(int i=0;i<N;i++){//
for(int j=0;j<=i;j++){
if(!j) c[i][j]=1;
else c[i][j]=(c[i-1][j]+c[i-1][j-1]) % mod;
}
}
}
int main()
{
init();
int n;
cin>>n;
for(int i=0;i<n;i++){
int a,b;
cin>>a>>b;
cout<<c[a][b]<<endl;
}
return 0;
}
快速幂
快速求解
将a的k次方中的k以二进制的形式表示,然后k=2的0次方+2的一次方+…
5=(101)二进制,5=2的0次方+2的2次方
2的1次方=(2的0次方)平方,2的2次方=(2的1次方)平方
模板
typedef long long LL;
LL qmi(int a,int k,int p){
LL res = 1%p;//res为返回的结果
while(k){
if(k & 1) res = res * a %p;
a=a*(LL)a%p;
k>>=1;
}
return res;
}
例题
#include<iostream>
using namespace std;
typedef long long LL;
LL qmi(int a,int k,int p){
LL res = 1%p;//res为返回的结果
while(k){
if(k & 1) res = res * a %p;//如果当前b的二进制写法中最后一位是1
//假设a=4,4的1次方=4的2的0次方,4的2次方=4的2的1次方=(4的2的0次方)平方
a=a*(LL)a%p;//假设a是4,4的5次方二进制可以表示为4(101)次方,4就是(001)次方,4*4就是(010)次方
//又移1位
k>>=1;
}
//对于mod解释,以4的5次方为例,4的5次方mod10=(4mod10)*(4mod10)...=(4*4mod10)*...*(4mod10)
return res;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
int a,k,p;
scanf("%d%d%d",&a,&k,&p);
cout<<qmi(a,k,p)<<endl;
}
return 0;
}