[bzoj 1053] [HAOI2007]反素数ant:数论,DAG上最短路

题意:设g(i) = i的约数个数,若对于某个正整数x,所有0<i<x都有g(i)<g(x),那么称x为反素数。求不大于n的最大反素数。(n<=2*10^9)

暑假的时候TYQ同学提到一个有趣的概念叫做反素数,看到bzoj第一页有这道题,于是来写一写。

关于约数个数,我们知道什么?约数个数定理:设 x=paii ,由乘法原理,约数个数 σ(x)=(ai+1) 。筛法可以线性地处理前缀的约数个数。然而,根据数据范围,这是不可行的。

设f(i)=约数个数为i的最小正整数,问题等价于求最小的f(i) <= n。能不能把它和约数个数定理结合起来呢?如果数据范围内所有x的约数个数都很小,暴力枚举一下是可行的。然而怎么估算约数个数呢?

又考虑了一下前缀的lcm,然而lcm(1, 2, 3)=6,lcm(1, 2, 4) = 4,f(3)=4。

反素数有没有什么神奇的性质呢?

看题解……第一条是百度百科,点进去看了一下,给了两条性质:1) 一个反素数的质因子必然是从2开始连续的质数 2) p=2^t1*3^t2*5^t3*7^t4…..必然t1>=t2>=t3>=….

性质一很显然的样子,性质二用逐步调整法容易证明。不看啦,再想一想。

性质一可以推出本题只用考虑前10个素数作为质因子。我想dp一下……于是,又回到那个老问题:如何估算约数个数?我似乎犯蠢啦, O(n) 啊……性质二在本题中没有发挥作用。

如果即时想到这个界,这道题就能算作自己想出来的啦 QAQ

取个对数,本题回到了我们所熟悉的DAG上最短路的模型。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int prime[11] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29}, inf = 2e9;
int n, f[11][89450];

int main()
{
    for (int i = 0; i < 11; ++i)
        for (int j = 0; j < 89450; ++j)
            f[i][j] = inf;

    scanf("%d", &n);
    int m = (sqrt(n)+1)*2;

    f[0][1] = 1;

    for (int i = 0; i < 10; ++i)
        for (int j = 1; j <= m; ++j) {
            ll x = f[i][j];
            for (int k = 0; x <= (ll)n; ++k, x *= prime[i+1])
                f[i+1][j*(k+1)] = min(f[i+1][j*(k+1)], (int)x);
        }

    for (int i = 89449; i; --i)
        if (f[10][i] < inf) {
            printf("%d\n", f[10][i]);
            break;
        }

    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值