【线性筛】ACM-ICPC 2018 南京赛区网络预赛 J. Sum

Step1 Problem:

n = a*b, 同时 a 的因数不存在平方数,b 的因数不存在平方数。(a != b,a 和 b 互换位置算不同的方案)
f(n):满足上述条件的方案数
例如 n = 4: 只有 (2, 2) 一种方案,因为 (1, 4), (4, 1) 中的 4 的因数存在平方数。
T组询问,每次给你一个 n, 让你输出 sum{ f(i) }, i = 1, 2, 3, …, n.
数据范围:
T<=20, n <= 2e7.

Step2 Ideas:

线性筛核心思路:保证每个合数只会被它的最小质因数筛去
我们线性求出 f(i), 预处理一波前缀和。
如何求 f(i):
如果 i 是质素:f(i) = 2
如果 i 不是质素:
我们求出 i 的最小质因数 p:
如果 p 的幂 = 1:f(i) = f(i/p) * 2;// p 可以放在小因数 或者 大因数 所以乘 2
如果 p 的幂 = 2:f(i) = f(i/(p^2));// p 得分开放在小因素 大因数那
如果 p 的幂 > 2:f(i) = 0;// 无论怎么放,因数都肯定包含平方数
线性筛的过程中,所有的合数我们都可以访问一遍,在访问的过程同时知道最小的质因数

Step3 Code:

#include<bits/stdc++.h>
using namespace std;
const int N = 2e7+5;
int prim[N], ans[N], cnt = 0;
bool vis[N];
void get_prim()
{
    memset(vis, 0, sizeof(vis));
    vis[0] = vis[1] = 1;
    ans[1] = 1;
    for(int i = 2; i < N; i++)
    {
        if(!vis[i]) {
            prim[cnt++] = i;
            ans[i] = 2;
        }
        for(int j = 0; j < cnt && prim[j]*i < N; j++) {//枚举 i 的最小质因数
            vis[prim[j]*i] = 1;
            if(i%prim[j] == 0) {//再往后就不是 i 的最小质因数了
                int t = i/prim[j];
                if(t%prim[j] == 0) {
                    ans[i*prim[j]] = 0;
                }
                else ans[i*prim[j]] = ans[t];
                break;
            }
            else {
                ans[prim[j]*i] = ans[i]*2;
            }
        }
    }
    ans[0] = 0;
    for(int i = 1; i < N; i++) {
        ans[i] += ans[i-1];
    }
}
int main()
{
    int T, n;
    get_prim();
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        printf("%d\n", ans[n]);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值