XTU-OJ 1377-Factorization

题目描述#

根据质因子唯一分解定理可知n=pk11pk22…pkmm,其中pi都是质数。我们定义f(n)=m, 求g(a,b)=∑bi=af(i)。

输入#

第一行是一个整数T(1≤T≤1000),表示样例的个数。

以后每个样例占一行,为两个整数 a(2≤a≤b≤106)。

输出#

依次每行输出一个样例的结果,为一个整数。

样例输入#

2
2 2
2 10

样例输出#

1
11

解题思路:这题还是质因数分解的题,另外 前缀和 肯定也是跑不了的。

但是这次换个不一样的解法,我们利用 欧拉筛 的筛法性质,来解这道题, 关键代码就17、19两行,如果能理解到,也是说明你对欧筛的理解完全ok了。   

首先知道,欧筛是一个线性筛,所有数只需要遍历一遍,就能判断出它是否为质数,这里,我们还是把质数标记为1(第13行),因为它本身质因数分解就它自己,所以就是 f(n) = 1。

然后17行,令 vis[i*prime[j]] = vis[i],即 f(i的倍数) = f(i),因为 i*prime[j]i * prime[j],我们默认这个 prime[j] 已经是 数字 的质因数,所以定义  f(i*n) = f(i)。

那什么时候执行19行,vis++操作? 当i % prime[j] != 0 ,即 prime[j] 是一个新的质因数时,vis++, (例如:i = 3 时,vis[3*2] = vis[3] = 1, 如果没有break掉,说明 i 以前没有2这个质因数,而这里 又有 i = 3*2,所以 vis[3*2] 要 ++(加上2这个因数))

以此类推,vis数组最后就 既是 质数的标记数组,又是 前缀和的记录数组 (vis的值,就是 f(i) 的值)

AC代码:

#include 

const int N = 1e6;
int vis[N+2] = {0};
int prime[80000] = {0};
void is_prime()
{
    for (int i = 2; i < N; i ++)                // 欧筛
    {
        if (!vis[i])
        {
            prime[++prime[0]] = i;
            vis[i] = 1;
        }
        for (int j = 1; j <= prime[0] && i <= N/prime[j]; j ++)
        {
            vis[i*prime[j]] = vis[i];
            if (i % prime[j] == 0)        break;
            vis[i*prime[j]] += 1;      // 如果没break掉,说明是prime[j]对i来说是一个新的质因数,同理是 i*prime[j]的新质因数
        }
    }
    for (int i = 2; i <= N; i ++)               // 前缀和
        vis[i] += vis[i-1];
}

int main()
{
    is_prime();
    int T;
    scanf("%d",&T);
    while ( T --)
    {
        int a,b;
        scanf("%d %d",&a,&b);
        printf("%d\n",vis[b]-vis[a-1]);
    }
    return 0;
}

你可能感兴趣的:(湘大OJ练习解析,算法,数据结构)