题意
给定n,求小于等于n的所有数中,因数和为自身的两倍的数有多少
限制:n 不大于500000
方法
质因子分解+预处理
一个整数只能被唯一质因数分解,设
那么的所有因数的和为
注意到,且的因数和为
所以的因数的和可以由的因数的和间接得到
例如样例的28
| - | 1 | 2 | 4 | 
|---|---|---|---|
| 1 | 1 | 2 | 4 | 
| 7 | 7 | 14 | 28 | 
因数和为
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int i = (a);i<(b);i++)
#define N 500000
ll mypow(ll v,ll pwr){ // 幂次计算
    ll r = 1;
    while(pwr){
        if(pwr%2)r*=v;
        v*=v;
        pwr/=2;
    }
    return r;
}
int main(){
    vector<ll> base(N+10,1); // 质数表
    vector<ll> sum(N+10,1); // 每个数的因数和
    vector<ll> ans(N+10,0); // 预处理答案
    rep(i,2,N+1){ // 初始化质数表
        if(base[i] != 1)continue;
        base[i] = i; // 是质数
        for(ll j = i*i;j<=N;j+=i){ // 筛数
            if(base[j] == 1)base[j] = i;
        }
    }
    rep(i,2,N+1){
        ll b = base[i]; // 找一个数的质因子
        int cnt = 0; // 该质因子幂次
        int ii = i; // 去掉这个质因子以外剩余部分
        while(ii % b == 0){ 
            cnt ++;
            ii/=b;
        }
        sum[i] = sum[ii] * (mypow(b,cnt+1)-1)/(b-1); // 所有质因子的和, 等比数列求和公式
        ans[i] = ans[i-1] + (sum[i] == i*2); // 是否满足题意,预处理答案
    }
    int n;
    while(~scanf("%d",&n)){
        printf("%d\n",ans[n]); // 直接输出
    }
    return 0;
}
复杂度分析
设询问次数为
时间复杂度: 质数表处理, 对每个数,计算它的因数和,最大质因子个数为log级别,所以, 计算答案,基于上面的结果,每次询问的查询代价,所以总时间复杂度为
空间复杂度: 空间主要耗在上面的三个vector,所以空间复杂度为
枚举
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int i = (a);i<(b);i++)
ll getsum(ll v){ 
    ll cnt = 0;
    rep(i,1,v+1){ // 枚举
        cnt += (v%i==0?i:0);
    }
    return cnt;
}
int main(){
    int n;
    while(~scanf("%d",&n)){
        int ans = 0; // 答案
        rep(i,2,n+1){
            ans += getsum(i) == i*2; // 是否满足题意,预处理答案
        }
        printf("%d\n",ans); // 直接输出
    }
    return 0;
}
复杂度分析
时间复杂度: 对于每个查询,枚举到n,所以时间复杂度为, 应该超时的,而数据太弱,竟然它过了
空间复杂度: 常数大小的额外空间消耗,所以空间复杂度为

京公网安备 11010502036488号