CodeForces 300E Empire Strikes Back

CodeForces 300E Empire Strikes Back

题目描述:

求最小正整数 N ,使得 N!Ki=1ai!

题解:

sum=Ki=1ai!

首先可以想到,对于每一个质数 pi ,找到最小的 Ni 使得 Ni! 中质因子 pi 的出现次数大于等于 sum 里的。

这个玩意儿显然可以二分,于是问题转变成如何求一个数的阶乘里有多少个 pi 因子,答案是 Nipki ,这部分的复杂度是 O(log2K)

再考虑如何求 sum 里质因子 pi 的个数。

numx 表示 sum 中因子 x 的出现次数。

如果不考虑阶乘里面的合数分解出来的因子的话,可以简单的求一下后缀和(详见代码),而之后对于一个合数 k ,我们可以用 numk 去更新 numprk numkprk 的值,其中 prk 表示 k 的最质数因子。这样的话每次总是用大数去更新小数,因此从大到小递推即可。

总复杂度 O(log sum log2K) ,大概。

题目链接: vjudge 原网站

代码:


#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <algorithm>
using namespace std;

#define MAXN 1000003
#define MAXV 10000003

static int N, pr_tot, np[MAXV];
static long long sum, mx, tmp, ans = 1, prime[MAXN], pr[MAXV], num[MAXV];

int main()
{
    for (long long i = 2; i < MAXV; i++)
    {
        if (!np[i]) pr[i] = prime[pr_tot++] = i;
        for (int j = 0; j < pr_tot && i * prime[j] < MAXV; j++)
        {
            np[i * prime[j]] = 1;
            pr[i * prime[j]] = prime[j];
            if (i % prime[j] == 0) break;
        }
    }
    scanf("%d", &N);
    for (int i = 0; i < N; i++)
        scanf("%lld", &tmp), sum += tmp, mx = max(mx, tmp), num[tmp]++;
    for (int i = mx; i > 1; i--) num[i-1] += num[i];
    for (int i = mx; i > 1; i--)
        if (np[i])
            num[pr[i]] += num[i], num[i / pr[i]] += num[i];
    for (int i = 0; i < pr_tot && num[prime[i]]; i++)
    {
        long long l = 1, r = sum, k;
        while (l <= r)
        {
            long long mid = (l + r) >> 1, tot = 0;
            for (tmp = mid; tmp; tmp /= prime[i])
                tot += tmp / prime[i];
            if (tot < num[prime[i]]) l = mid + 1; else r = (k = mid) - 1;
        }
        ans = max(ans, k);
    }
    printf("%lld\n", ans);
    return 0;
}

提交记录(AC / Total = 1 / 4):

Run IDRemote Run IDTime(ms)Memory(kb)ResultSubmit Time
849960625658399466131000WA2017-03-20 11:08:20
849961115658414404131000WA2017-03-20 11:10:17
849964725658464560134912RE2017-03-20 11:16:09
8499658256584822650205372AC2017-03-20 11:19:05
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值