您的位置:首页 > 其它

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

2016-12-04 14:52 411 查看
题意:设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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息