2021年“图森未来杯”全国程序设计邀请赛 D. Divide(阶乘质因数分解)

传送门


题目大意

给出两段区间 [ l 1 , r 1 ] , [ l 2 , r 2 ] [l_1, r_1] ,[l_2, r_2] [l1,r1],[l2,r2],设 d 1 = ∏ i = l 1 r 1 , d 2 = ∏ i = l 2 r 2 d_1 = \prod_{i = l_1}^{r_1}, d_2 = \prod_{i = l_2}^{r_2} d1=i=l1r1,d2=i=l2r2,问是否 d 1 ∣ d 2 d_1 | d_2 d1d2,即前者整除后者。

解题思路

这题拿到思路后一直想着对每个数质因数分解的方法去求,但是无奈要么 T L E TLE TLE要么 M L E MLE MLE,实际上单纯的质因数分解已经差不多接近超时了,如果再加上 u n o r d e r e d _ m a p unordered\_map unordered_map的常数肯定就挂了。

质因数层面很好想,就是对于第一个乘积的每个质因数的幂次,必定小于等于第二个乘积中的幂次。乘积无法维护,对每个数质因数分解常数很大,于是我们可以转化一下,根据前缀和的思想也就是 d 1 = r 1 ! ( l 1 − 1 ) ! , d 2 = r 2 ! ( l 2 − 1 ) ! d_1 = \frac{r_1!}{(l_1 - 1)!}, d_2 = \frac{r_2!}{(l_2 - 1)!} d1=(l11)!r1!,d2=(l21)!r2!,然后只需要枚举所有的质数,求阶乘质因数的时间复杂度为 O ( l o g n ) O(logn) O(logn),设 1 e 7 1e7 1e7内质数的个数为 m m m,那么本题的时间复杂度就是 O ( m l o g n ) O(mlogn) O(mlogn)

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define ENDL "\n"
const int maxn = 1e7 + 10;

vector<int> prime;
bitset<maxn> vis;

void euler() {
    for (int i = 2; i < maxn; i++) {
        if (!vis[i]) prime.push_back(i);
        for (int j = 0; j < prime.size() && 1LL * i * prime[j] < maxn; j++) {
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) break;
        }
    }
}

ll cal(int n, int p) {
    ll ans = 0;
    while (n) {
        ans += n / p;
        n /= p;
    }
    return ans;
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T, l, r, L, R;
    euler();
    cin >> T;
    while (T--) {
        cin >> l >> r >> L >> R;
        bool ok = 1;
        for (auto p : prime) {
            ll x = cal(r, p) - cal(l - 1, p), y = cal(R, p) - cal(L - 1, p);
            if (x > y) {
                ok = 0;
                break;
            }
        }
        if (ok)
            cout << "Yes" << ENDL;
        else
            cout << "No" << ENDL;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值