AtCoder Beginner Contest 280 D题 Factorial and Multiple

题意很简单,给定一个整数x,范围<1e12,求最小的正整数n,使得n的阶乘可以整除x

将x分解成素数积,可以注意到一个事实,即n的阶乘可以整除x,那么对于任意x的一个素数,将n的阶乘分解成素数积后,该素数的数量一定大于等于x的数量。

对于每个素数,我们单独考虑

假设当前素数为x,数量为y,显然n的大小具有二分性,即n越大,对应数目一定越多。

我们可以二分n,直至找到最小的n,满足n的阶乘的x的因子数目>=y

如何二分:

考虑容斥,对于素因子x来说,具有该因子的数字一定是x的倍数,但一个数字显然可能具有多个x因子,所以容斥,枚举x的1,2,3...次方的倍数对答案贡献

也有其他做法:由于x不是很大,素因子不会有很多个,每个素因子的数目也不会很多,我们直接枚举素因子x的倍数,算出每个倍数有多少个素因子即可

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
#define int  long long 
typedef pair<int, int>pii;
typedef pair<int, double>pid;
typedef pair<int, pii>piii;
const int mod = 1e9 + 7;
const int N = 2e5 + 100;
int poww(int a, int b) { int ans = 1; if (b == 0)return 1; for (int i = 1; i <= b; i++)ans = ans * a; return ans; }

unordered_map<int, int>syz;

int ck(int n, int x, int y)
{
    int ds = x;
    int sum = 0;
    int bk = x;
    while (ds <= n)
    {
        sum += n / ds;
        if (sum >= y)return 1;

        ds = ds * x;
        if (ds <= bk)return 0;
        bk = ds;
    }
    return 0;
}


void solve()
{
    int n; cin >> n;
    int fl = 0;
    int bk = n;
    for (int i = 2; i * i <= n; i++)
    {
        if (n % i == 0)fl = 1;
    }
    if (fl == 0)cout << n;
    else
    {
        int mx = 0;
        for (int i = 2; i * i <= n; i++)
        {
            if (n % i == 0)
            {
                while (n % i == 0)
                {
                    syz[i]++;
                    n /= i;
                }
            }
        }
        if (n > 1)syz[n]++;
        int ans = -1;
        for (auto [x, y] : syz)
        {
            int l = 1, r = 1e12;
            while (l < r)
            {
                int mid = (l + r) >> 1;
                if (ck(mid, x, y))r = mid;
                else l = mid + 1;
            }
            ans = max(ans, l);
        }
        cout << min(ans, bk);
    }
}


signed main()
{
    ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
    int t = 1;
    //  cin >> t;
    while (t--)solve();
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值