目录
【一. 整除与约数】
1.整除的基本概念
2.取整除法
(1)取整除法的概念和应用
(2)取整除法求和
怎么计算sum{ [n/i] }?(1<=i<=n) (n<=10^13)
n太大,硬算肯定不行,我们先观察一个例子,看能否得出一些结论。
当n=20时,和式展开 20+10+6+5+4+3+2+2+2+2+1+1+1+1+1+1+1+1+1+1
注意到后面相同的数太多,不妨化简下:
20+10+6+5+1*(20-10)+2*(10-6)+3*(6-5)+4*(5-4)
=(20+10+6+5)+(20+10+6+5)-4*4
=2(20+10+6+5)-4*4
这样,复杂度就从O(n)降为O(√n)了。
程序实现(求根号n之前的所有n/i,再根据公式得出答案)
ll ans(ll n){
ll anss = 0, nn = sqrt(n) ;
for (ll i = 1; i <= nn; i++) anss += n / i;
return (anss << 1) - nn * nn;
}
3.因子和约数
(1)基础概念
- 平凡因子:1和自身。
- 若p是质数,则p没有非平凡因子。
- 若p没有非平凡因子,则p是质数。
(2)求N的正约数集合——试除法
约数总是成对出现的。只需要扫描因子d=1~√n。
int factor[1600],m=0;
for(int i=1;i*i<=n;i++){
if(n%i==0){
factor[++m]=i;
if(i!=n/i) factor[++m]=n/i;
}
}
for(int i=1;i<=m;i++)
cout<<factor[i]<<endl;
(3)试除法的推论
一个整数N的约数个数上界,为2√N。
(4)求1~N每个数的正约数集合——倍数法
vector<int>factor[500010];
for(int i=1;i<=n;i++)
for(int j=1;j<=n/i;j++)
factor[i*j].push_back(i);
for(int i=1;i<=n;i++){
for(int j=0;j<factor[i].size();j++)
printf("%d ",factor[i][j]);
printf("\n");
}
(5)倍数法的推论
1~N每个数的约数个数总和,大约为N*logN。
【例题】洛谷 p1403 约数研究
< 法1 > 倍数法筛因子个数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
/*【洛谷p1403】约数研究【法1:倍数法筛因子个数】
f(n)表示n的约数个数,现在给出n,要求求出f(1)到f(n)的总和。 */
int p[1000100],n;
void reads(int &x){ //读入优化(正负整数)
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f; //正负号
}
void init(){ //倍数法求因数个数
memset(p,0,sizeof(p));
for(int i=1;i<=n;i++)
for(int j=1;j<=n/i;j++)
p[i*j]++;
}
int main(){
int sum=0; reads(n); init();
for(int i=1;i<=n;i++) sum+=p[i];
printf("%d\n",sum);
}
< 法2 > 归纳统计法
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
/*【洛谷p1403】约数研究
f(n)表示n的约数个数,现在给出n,要求求出f(1)到f(n)的总和。 */
void reads(int &x){ //读入优化(正负整数)
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f; //正负号
}
int main(){
int n,sum=0; reads(n);
for(int i=1;i<=n;i++) sum+=n/i;
printf("%d\n",sum);
}
【例题】 bzoj 1053 Antiprime数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
/*【bzoj1053】caioj 1411 打牌
对于任何正整数x,其约数的个数记作g(x)。例如g(1)=1、g(6)=4。
如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数。
例如,整数1,2,4,6等都是反质数。
现在给定一个数N,你能求出不超过N的最大的反质数么 */
/*【分析】通过计算可以得出,
一个2000000000以内的数字不会有超过12