赛克oj 1541(线性筛、约数个数)
赛氪OJ-专注于算法竞赛的在线评测系统 (saikr.com)
题目描述
小明在学校学了质数和合数的知识后,便想知道对于任意的一个数N,将其拆分为一个质数与一个合数相加的结果,有几种拆法?
但后来想想又觉得太简单了,于是他追加了一些条件,合数要继续拆分为两个数相乘的形式才行,那么满足以上条件的关于N的等式有几种?
换句话来讲,你需要找出满足以下条件的等式的数量:
𝐴×𝐵+𝐶=𝑁(𝐴,𝐵>0,𝐶≥2,𝐴×𝐵A×B+C=N(A,B>0,C≥2,A×B 结果为合数,𝐶C 为质数))
需要注意的是,小明根据质数的定义,把11也归为了合数,所以1×11×1也可以算一个𝐴×𝐵A×B 。
输入
输入格式:
- 输入一行一个数n
输出
输出格式:
- 输出一行一个数,表示等式数量
线性筛模板来自线性筛求 约数个数 与 约数和 - 糖豆爸爸 - 博客园 (cnblogs.com) -
1 #define IO std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) 2 #define bug(x) cout<<#x<<" is "<<x<<endl 3 #include <bits/stdc++.h> 4 #define iter ::iterator 5 using namespace std; 6 typedef long long ll; 7 typedef pair<int,int>P; 8 #define pb push_back 9 #define mk make_pair 10 #define se second 11 #define fi first 12 #define rs o*2+1 13 #define ls o*2 14 const int N = 2e7+5; 15 16 int primes[2000000], cnt; // primes[]存储所有素数 17 bool st[N]; // st[x]存储x是否被筛掉 18 int d[N]; // d[x]表示x的约数个数 19 int num[N]; // num[x]表示x的最小质因数的个数 20 int n; 21 //欧拉筛法+求约数个数 22 void get_primes(int n) { 23 d[1] = 1; // 1的约数只有1个,这个比较特殊 24 25 for (int i = 2; i <= n; i++) { 26 if (!st[i]) { 27 primes[cnt++] = i; 28 // i是质数 29 d[i] = 2; //约数个数是2个,一个是1,另一个是i 30 num[i] = 1; //最小质因子个数是1,最小质因子就是自己i 31 } 32 33 for (int j = 0; i <= n/primes[j]; j++) { 34 st[i * primes[j]] = true; 35 if (i % primes[j] == 0) { 36 d[i * primes[j]] = d[i] / (num[i] + 1) * (num[i] + 2); 37 num[i * primes[j]] = num[i] + 1; 38 break; 39 } else { 40 // d[i * primes[j]] = d[i] * d[primes[j]]; 等价于下面的代码 41 d[i * primes[j]] = d[i] * 2; 42 num[i * primes[j]] = 1; 43 } 44 } 45 } 46 } 47 48 int main() { 49 //scanf("%d", &n); 50 //n=2e7; 51 //cin>>n; 52 IO; 53 cin>>n; 54 get_primes(n-1); 55 //输出1~n之间所有数字的约数个数 56 ll ans=0; 57 for(int i=0;i<cnt;i++){ 58 int x=primes[i]; 59 int y=n-x; 60 if(y==1){ 61 ans++; 62 continue; 63 } 64 if(st[y])ans+=d[y]; 65 } 66 cout<<ans<<endl; 67 68 69 //for (int i = 1; i <= n; i++) printf("%d %d\n", i, d[i]); 70 return 0; 71 }