hdu 6069 Counting Divisors

2023-10-30

Problem

acm.hdu.edu.cn/showproblem.php?pid=6069

Meaning

定义函数d(n) = n 的因子个数
给定区间 [ l , r ] 和常数 k,求

( i = lrd(ik) ) mod 998244353

Analysis

朴素的想法,先把每一个 i 都质因数分解, i=pe11penn ,于是 ik 对答案的贡献就是 (e1k+1)(e2k+1)(enk+1) ,最后答案就是:

( i=lrj=1n(ejk+1) ) mod 998244353

就先打一个 106 的素数表(如果有大于 106 的质因子,那么只能有一个,并且指数为 1),然后枚举 [ l , r ] 里的数,对每一个都做一次质数分解、统计答案,超时。
一种优化:对于某个 i,质因子分别为 p1pn ,那么在处理完 ik 的贡献后,可以一并处理掉 (ie1)k(ien)k 的贡献,因为它们只间只有其中一个因式 (ejk+1) 变成 ((ej+1)k+1) 这一个差别,这样就可以少做一些质因数分解(有点像素筛的过程),但还是超时。
可能主要是因为每次质因数分解都要扫一遍质数表,做了很多无用功。
反过来想,不从 i 分解质因子,而是用个数组装下区间[l , r]和它们的贡献(初始为 1),枚举 106 内的质数,对每一个质数 p,在区间内找它的倍数来拆(分解),拆完之后更新这个数的贡献,最后再把贡献求和。

Code

#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1000000, MOD = 998244353;

int prime[N+1], top; // prime table

void sieve()
{
    top = 0;
    memset(prime, -1, sizeof prime);
    for(int i = 2; i <= N; ++i)
    {
        if(prime[i])
            prime[top++] = i;
        for(int j = 0; j < top && prime[j] <= N / i; ++j)
        {
            prime[i * prime[j]] = 0;
            if(i % prime[j] == 0)
                break;
        }
    }
}

long long cntr[N+1]; // 区间内每个数的贡献
long long num[N+1]; // 区间内的数

int main()
{
    sieve();
    int T;
    scanf("%d", &T);
    while(T--)
    {
        long long l, r, k;
        scanf("%I64d%I64d%I64d", &l, &r, &k);
        for(int i = 0; i <= r - l; ++i)
        {
            num[i] = l + i;
            cntr[i] = 1;
        }
        for(int i = 0, p, beg; i < top; ++i)
        {
            p = prime[i];
            beg = (p - l % p) % p; // 区间里第一个是p倍数的数的下标
            // 枚举 p 的倍数
            for(int j = beg, cnt; j <= r - l; j += p)
            {
                // 质数分解
                for(cnt = 0; num[j] % p == 0; num[j] /= p)
                    ++cnt;
                // 更新贡献
                cntr[j] = cntr[j] * (cnt * k + 1) % MOD;
            }
        }
        // 补上大于 1e6 的质因数的贡献
        for(int i = 0; i <= r - l; ++i)
            if(num[i] > 1)
                cntr[i] = cntr[i] * (k + 1) % MOD;
        long long ans = 0;
        for(int i = 0; i <= r - l; ++i)
            ans = (ans + cntr[i]) % MOD;
        printf("%I64d\n", ans);
    }
    return 0;
}

TLE Code

#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1000000, MOD = 998244353;

struct node
{
    int v; // 因子的值
    int num; // 因子的指数
} dv[N+10]; // 分解出来的因子

long long prime[N+10], top, d;
bool vis[N+10]; // 标记这个数有没有被处理过

void seive(int n) {
    top = 0;
    memset(prime, -1, sizeof prime);
    for(int i = 2; i <= N; ++i)
        if(prime[i])
        {
            prime[top++] = i;
            for(int j = i; j <= N; j+=i)
                prime[j] = 0;
        }
}

// 快速幂
long long fpow(long long a, long long b)
{
    long long ans = 1;
    for( ; b; b >>= 1, a = a * a % MOD)
        if(b & 1)
            ans = ans * a % MOD;
    return ans;
}

// 逆元
long long inv(long long a)
{
    return fpow(a, MOD - 2);
}

// 质因数分解
void dvide(long long x)
{
    d = 0;
    for(int i = 0; i < top && prime[i] * prime[i] <= x; ++i)
        if(x % prime[i] == 0)
        {
            dv[d].v = prime[i];
            dv[d].num = 0;
            while(x % prime[i] == 0)
            {
                ++dv[d].num;
                x /= prime[i];
            }
            ++d;
        }
    if(x != 1)
    {
        dv[d].v = x;
        dv[d++].num = 1;
    }
}

int main() {
    int t;
    scanf("%d", &t);
    seive(N);
    while(t--) {
        long long l, r;
        int k;
        scanf("%lld%lld%d", &l, &r, &k);
        memset(vis, false, sizeof vis);
        long long ans = 0;
        for(long long i = l, tmp; i <= r; ++i)
        {
            if(vis[i - l])
                continue;
            vis[i - l] = true;
            dvide(i); // 分解
            tmp = 1; // 贡献
            for(int j = 0; j < d; ++j)
                tmp = tmp * (dv[j].num * k + 1) % MOD;
            ans = (ans + tmp) % MOD;
            // 顺便处理 i * ej 的贡献
            for(int j = 0; j < d && i * dv[j].v <= r; ++j)
            {
                if(vis[i * dv[j].v - l])
                    continue;
                vis[i * dv[j].v - l] = true;
                ans = (ans + tmp + (tmp * inv(dv[j].num * k + 1) % MOD * k)) % MOD;
            }
        }
        printf("%lld\n", ans % MOD);
    }
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

hdu 6069 Counting Divisors 的相关文章

随机推荐

  • 三维气体扩散模拟matlab仿真

    目录 1 算法仿真效果 2 MATLAB源码 3 算法概述 4 部分参考文献 1 算法仿真效果 matlab2022a仿真结果如下 2 MATLAB源码 订阅用户可以获得任意一份完整代码 私信博主 留言文章链接和邮箱地址 一般第二天下午4点
  • 什么是静态变量和静态方法?如何在Java中使用它们?什么是同步和异步?如何在Java中进行同步和异步编程?什么是单元测试?如何在Java中进行单元测试?

    单元测试是一种软件测试方法 它用于测试一个软件系统的最小可测试单元 在Java中 JUnit是最常用的单元测试框架之一 它提供了一些注解和断言 可以方便地编写和运行测试用例 除了JUnit之外 Mockito也是一个非常有用的测试框架 它允
  • (转) 如何将notepad++添加到右键

    工具 原料 win 7系统 Notepad 方法 步骤 左下角点击 开始 gt 运行 gt regedit 打开注册表编辑器 在HKEY CLASSSES ROOT Shell 下 在Shell下 新建项命名为Open With Notep
  • 卧槽,做Python兼职又接了一个大单,真香

    每年的第一季度 是Python兼职接单的高潮期 近段时间 各行业对爬虫类和数分类服务的需求量呈指数级的暴增 圈子里的朋友双休都没闲着 趁着旺季接单大赚一笔 所以 最近在csdn后台咨询技术变现 兼职接单问题的朋友也越来越多 最近十天收到了六
  • 【数据库原理及应用教程(第4版

    文章目录 一 选择题 二 填空题 三 简答题 Reference 一 选择题 1 2 3 4 5 6 7 8 9 10 C B D C D B A B D B 11 12 13 14 15 16 17 18 19 20 C D A D B
  • Spring启动执行流程梳理

    注 本文梳理启动流程使用的Spring版本 4 0 2 RELEASE 使用spring配置 都需要在web xml中配置一个spring的监听器和启动参数 context param 如下
  • 基于视觉的移动平台运动目标检测

    1 声明 本文为自己的研究总结 主要根据各类文献总结而来 内容上可能有些不全面 不客观 这篇博文主要介绍的是基于视觉的移动平台运动目标检测 写这篇博文的目的主要是对自己一个阶段性总结 也希望能够帮助做这方面研究的同学 2 引言 首先 我们来
  • Nacos + Prometheus + Grafana 搭建走起~

    小伙伴们好呀 这两天在本地搭建了这个 Nacos Prometheus Grafana 主要是为了这个 nacos 填坑 然后顺便搭下这个监控中心 哈哈 文章内容比较琐碎 看完你可以了解到 怎么选择 nacos 版本 可能会踩到的坑 没错
  • 一些概念的解释

    转移支付 财政转移支付是以各级政府之间所存在的财政能力差异为基础 以实现各地公共服务水平的均等化为主旨 而实行的一种财政资金转移或财政平衡制度 用人话说 就是大家一起收税 三分留地方 七分归国家 实际上不同税种比例不同 归国家的这些国家在根
  • DELL R740服务器系统安装详细过程

    RAID配置 1 开机F2进入bios 2 选择device setting 3 Integrated Raid controller 1 xxxxxx raid 卡型号 一般是第一行 4 选择 Main Menu
  • java中上传本地图片

    如果你想上传多张图片 http blog csdn net xuanzhangran article details 54929988 如果是上传单张如下 点击上传图片按钮 上传本地 效果如图 1 原始图框 2 点击预览 弹出本地弹框 3
  • PB调用windows api删除文件夹及其子文件夹或子文件

    创建nvo folder对象 forward global type nvo folder from nonvisualobject end type type shfileopstruct from structure within nv
  • Java线程:线程的交互

    本文转载至 http lavasoft blog 51cto com 62575 99157 线程交互是比较复杂的问题 SCJP要求不很基础 给定一个场景 编写代码来恰当使用等待 通知和通知所有线程 一 线程交互的基础知识 SCJP所要求的
  • 比较流行的响应式框架

    Bootstrap Foundation Semantic UI PureCSS 与君共勉 再牛逼的梦想 也抵不住傻逼般的坚持
  • Parser-Free Virtual Try-on via Distilling Appearance Flows代码解析

    从PF AFN test开始看 先看测试代码 1 test sh python test py name demo resize or crop None batchSize 1 gpu ids 0 参数 name resize or cr
  • 子组件自定义事件,父组件调用记录-

    方式一 1 子组件 p 某个事件 p methods a b是子组件自定义的事件名 this emit b 定义传给父组件的值 2 父组件调用 父组件定义 a a methods a e console log e 定义传给父组件的值 方式
  • 华为OD机试 - 运维日志排序(Java)

    题目描述 运维工程师采集到某产品线网运行一天产生的日志n条 现需根据日志时间先后顺序对日志进行排序 日志时间格式为H M S N H表示小时 0 23 M表示分钟 0 59 S表示秒 0 59 N表示毫秒 0 999 时间可能并没有补全 也
  • utils:常见的几种日期格式和转换方法

    一 UTC格式 国际统一时间 YYYYMMDD T HHMMSS Z 或者时区标识 T表示分隔符 Z表示的是UTC 相差北京时间8小时 2020 01 13T16 00 00 000Z 对应的北京时间 2020 01 14 00 00 00
  • 【计算机视觉】目标检测中Faster R-CNN、R-FCN、YOLO、SSD等算法的讲解(图文解释 超详细必看)

    觉得有帮助请点赞关注收藏 一 基于候选区域的目标检测算法 基于候选区域的深度卷积神经网络 Region based Convolutional Neural Networks 是一种将深度卷积神经网络和区域推荐相结合的物体检测方法 也可以叫
  • hdu 6069 Counting Divisors

    Problem acm hdu edu cn showproblem php pid 6069 Meaning 定义函数d n n 的因子个数 给定区间 l r 和常数 k 求 i lrd ik mod 998244353 sum r i