2021/4/9
2021/4/10
acwing学习笔记、分享一下
一、质数
在大于1的整数中, 如何只包含1和本身这2个约数,就被称为 质数 ,也叫素数
(1) 质数的判定——试除法
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
bool is_prime(int n){
if(n<2) return false;
for(int i=2;i<=n/i;i++){
if(n%i==0) return false;
}
return true;
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
int a;
cin>>a;
if(is_prime(a)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
(2) 分解质因数——试除法
#include<bits/stdc++.h>
using namespace std;
void divide(int n){
for(int i=2;i<=n/i;i++){ // n/i
if(n%i==0){ //n不包含任何从2到i-1之间的质因子(已经被除干净了)
//(n%i==0)所以i也不包含何从2到i-1之间的质因子,由质数的定义可知,保证了i是质数
int s=0;
while(n%i==0) n/=i,s++;
cout<<i<<' '<<s<<endl;
}
}
if(n>1) cout<<n<<' '<<1<<endl; //最多只有一个大于根下n的质因子(两个相乘就大于n了)
cout<<endl;
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
int a;
cin>>a;
divide(a);
}
}
(3) 筛质数
朴素筛法求素数
O(nlognlogn)埃式筛法
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6+5;
int primes[N],cnt;
bool st[N];
void get_primes(int n) // 埃式筛法
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i]){
primes[cnt ++ ] = i;
for (int j = i+i; j <=n; j +=i ) st[j]=true;
}
}
}
int main()
{
int n;
cin >> n;
get_primes(n);
cout<<cnt<<endl;
return 0;
}
线性筛质数
保证每个数被自己最小质因子筛选掉
ps:
9 i= 3 pj=3 筛掉
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6+5;
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;
//primes[j]<=n/i:变形一下得到——primes[j]*i<=n,把大于n的合数都筛了就没啥意义了
for (int j = 0; primes[j] <= n / i; j ++ ) // 从小到大枚举每个质数
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) break; //primes[j]一定是i的最小质因子
//
}
}
}
int main()
{
int n;
cin >> n;
get_primes(n);
cout<<cnt<<endl;
return 0;
}
二、约数
试除法求约数
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> get_div(int n){
vector<int> res;
for(int i=1;i<=n/i;i++){
if(n%i==0){
res.push_back(i);
if(i!= n/i) res.push_back(n/i);
}
}
sort(res.begin(),res.end());
return res;
}
int n;
int main()
{
cin>>n;
while(n--){
int x;
cin>>x;
auto res = get_div(x);
for(int i=0;i<res.size();i++)
cout<<res[i]<<' ';
cout<<endl;
}
return 0;
}
约数个数和约数之和
如果 N = p1^c1 * p2^c2 * … *pk^ck
约数个数: (c1 + 1) * (c2 + 1) * … * (ck + 1)
约数之和: (p1^0 + p1^1 + … + p1^c1) * … * (pk^0 + pk^1 + … + pk^ck)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int MOD = 1e9+7;
int main()
{
int n,x;
map<int,int> m;
cin>>n;
while(n--){
cin>>x;
for(int i=2;i<=x/i;i++){
while(x%i==0){
m[i]++;
x/=i; //方便求得约数的数量
}
}
if(x>1) m[x]++; //x的最大公约数可能大于sqrt(x);
}
long long res = 1;
for(map<int,int >::iterator p =m.begin();p!=m.end();p++){ // iterator 迭代器 * 指针类型
// cout<<'p'<<(*p).first<<' '<<(*p).second<<endl;
res=res*((*p).second+1)%MOD; // 公式
}
// 或者auto
// map<int,int> m;
// for(auto p:m){
// cout<<'p'<<p.first<<' '<<p.second<<endl;
// res=res*(p.second+1)%MOD;
// }
cout<<res<<endl;
return 0;
}
约数之和: (p10+p11+…+p1c1)∗…∗(pk0+pk1+…+pkck)(p10+p11+…+p1c1)∗…∗(pk0+pk1+…+pkck)
while (b – ) t = (t * a + 1) % mod;
t=t∗p+1
t=1
t=p+1
t=p2+p+1
……
t=pb+pb−1+…+1
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
const int MOD = 1e9+7;
int n,x;
int main()
{
cin>>n;
map<int,int> map;
while (n -- ){
cin>>x;
for(int i=2;i<=x/i;i++)
{
while(x%i==0){
map[i]++;
x/=i;
}
}
if(x>1) map[x]++;
}
ll res = 1;
for(auto p:map){
int a = p.first,b = p.second;
ll t= 1;
while(b--) t=(t*a+1)%MOD;
res= res*t%MOD;
// res=res*(p.second+1)%MOD;
}
cout<<res<<endl;
return 0;
}