Codeforces Round #677 (Div. 3) C. Division 质因子分解+思维

贪心+快速幂+思维C. Division

题目大意

给定p和q,求一个最大的x,使得x能整除p且不能被q整除。

解题思路

特判:若p不能被q整除(q不是p的因子),直接输出p,即为满足条件的x。

否则q一定是p的因子,那么这样的话有什么特点呢?

pq一定都可以被分解成很多的质因子,而对于每一个质因子i来说,pi的数目一定大于等于qi的数目(否则不能整除了)。

因此,实际上就是把q中某个质因子拿掉一个,设拿掉之后数目为cnt,让p中这个质因子的数目变成cnt,得到x,那么就满足xp的因子(因为只是拿掉了部分的质因子)且不能被q整除(因为某个质因子的数目变少了)。

那么为了找到最大的x,就对q的质因子一个个枚举即可,每次只拿掉一个质因子,更新答案。

其实直接从2开始逐个枚举q的因子也是一样的。

参考代码

我做的还有点复杂,专门统计了q的质因子个数。之后计算的时候用到了快速幂。

#include<bits/stdc++.h>
using namespace std;
#define LOCAL  //提交的时候一定注释
#define _for(i, a, b) for(int i = (a); i < (b); ++i)
#define _rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define pb push_back
#define VI vector<int>
#define maxn 100000
#define INF 0x3f3f3f3f
typedef long long LL;
typedef double db;
const double eps = 1e-6;  //定义浮点数误差

struct factor{
    
    
    int x, cnt;
}fac[20];

int readint(){
    
    
    int x; scanf("%d", &x); return x;
}

int notPrime[maxn];
LL prime[maxn];

int getP() {
    
    
    int primeN = 0;
    _for(i, 2, maxn) {
    
    
        if (!notPrime[i]) {
    
    
            prime[primeN++] = i;
            for(int j = i + i; j < maxn; j += i) {
    
    
                notPrime[j] = 1;
            }
        }
    }
    return primeN;
}

int quick(int a, int b) {
    
      //快速幂
    int res = 1;
    while (b) {
    
    
        if (b & 1) res = res * a;
        a *= a;
        b >>= 1;
    }
    return res;
}

int main() {
    
    
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
#endif
    int primeN = getP();
    //_for(i, 0, maxN) printf("%d", prime[i]);
    int t;
    LL p, q;
    scanf("%d", &t);
    while (t--) {
    
    
        scanf("%lld%lld", &p, &q);
        _for(i, 0, 20) {
    
    fac[i].cnt = 0;}
        int num = 0;
        //求q的所有质因子及对应的数目
        LL tmp = q;
        for(int i = 0; i < primeN && prime[i] <= (int)sqrt(1.0*tmp); i++) {
    
    
            if (tmp % prime[i] == 0) {
    
    
                fac[num].x = prime[i];
                fac[num].cnt = 0;
                while (tmp % prime[i] == 0) {
    
    
                    fac[num].cnt++;
                    tmp /= prime[i];
                }
                num++;
            }
            if (tmp == 1) break;
            //printf("%d\n", prime[i]);
        }
        if (tmp != 1) {
    
    
            fac[num].x = tmp;
            fac[num++].cnt = 1;
        }
        LL ans = -1;
        if (p % q) printf("%lld\n", p);  //特判,直接输出
        else {
    
    
            _for(i, 0, num) {
    
    
                LL t = p;
                while (t % fac[i].x == 0) {
    
    
                    t /= fac[i].x;
                }
                ans = max(ans, t * quick(fac[i].x, fac[i].cnt - 1));  //p先把原来的该质因子都除掉,只留下q中数目-1,保证不能被q整除
            }
            printf("%lld\n", ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Encore47/article/details/109448194