POJ - 2429 GCD & LCM Inverse(Pollard_rho质因数分解+搜索)

传送门


题目大意:

给出两个数的 g c d , l c m gcd,lcm gcd,lcm,问这两个数为多少时使得二者的和最小

分析:

根据最大公因数的性质,两个数的 g c d gcd gcd为其相同质因子指数的 m i n min min;同理最小公倍数的性质,两个数的 l c m lcm lcm为其相同质因子指数的 m a x max max。那么显然我们对 g c d , l c m gcd,lcm gcd,lcm分别质因数分解,最后操作分解出来的 l c m lcm lcm中不同的质因子,然后 d f s dfs dfs求出最小的 a + b a+b a+b

显然分解两个数太麻烦了,因为 l c m lcm lcm含有 g c d gcd gcd的所有质因子,且个数一定是大于等于的,那么我们只需要对 l c m / g c d lcm/gcd lcm/gcd分解质因数,然后求出的结果分解乘一个 g c d gcd gcd

吐槽一波,这题快速乘wa了十几发,多次仔细对比网上题解,改了龟速乘就过了,无语

//
// Created by Happig on 2020/8/18
//
#include <cstdio>
#include <math.h>
#include <map>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <iostream>

using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define Vector Point
#define lowbit(x) (x&(-x))
#define mkp(x, y) make_pair(x,y)
#define mem(a, x) memset(a,x,sizeof a);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double dinf = 1e300;
const ll INF = 1e18;
const int Mod = 1e9 + 7;
const int maxn = 1e4 + 10;

struct BigIntegerFactor {
    const static int maxm = 1e6 + 10;
    ll prime[maxm], p[maxm], sz, cnt;
    ll fac[10010], num[10010];

//    inline ll mul(ll a, ll b, ll p) {   //wa了尝试下面的慢速乘或者改为__int128
//        if (p <= 1000000000) return a * b % p;
//        else if (p <= 1000000000000LL) return (((a * (b >> 20) % p) << 20) + (a * (b & ((1 << 20) - 1)))) % p;
//        else {
//            ll d = (ll) floor(a * (long double) b / p + 0.5);
//            ll ret = (a * b - d * p) % p;
//            if (ret < 0) ret += p;
//            return ret;
//        }
//    }

    inline ll mul(ll a, ll b, ll Mod) {
        ll ans = 0;
        while (b) {
            if (b & 1) ans = (ans + a) % Mod;
            a = (a + a) % Mod;
            b >>= 1;
        }
        return ans;
    }

    void init(int up) {  //传入的参数不能超过maxm,根据数据范围来定,1e5wa了就改1e6试试
        int tot = 0;
        sz = up - 1;
        for (int i = 1; i <= sz; i++) p[i] = i;
        for (int i = 2; i <= sz; i++) {
            if (p[i] == i) prime[tot++] = i;
            for (int j = 0; j < tot && 1LL * i * prime[j] <= sz; j++) {
                p[i * prime[j]] = prime[j];
                if (i % prime[j] == 0) break;
            }
        }
    }

    inline ll qkp(ll x, ll n, ll p) {
        ll ans = 1;
        while (n) {
            if (n & 1) ans = mul(ans, x, p);
            x = mul(x, x, p);
            n >>= 1;
        }
        return ans;
    }


    inline bool check(ll a, ll n) {
        ll t = 0, u = n - 1;
        while (!(u & 1)) t++, u >>= 1;
        ll x = qkp(a, u, n), xx = 0;
        while (t--) {
            xx = mul(x, x, n);
            if (xx == 1 && x != 1 && x != n - 1) return false;
            x = xx;
        }
        return xx == 1;
    }

    inline bool miller(ll n, ll k) {  //检测一个数n是否为素数,一般k取20即可
        if (n == 2) return true;
        if (n < 2 || !(n & 1)) return false;
        if (n <= sz) return p[n] == n;
        for (int i = 0; i <= k; i++) {
            if (!check(rand() % (n - 1) + 1, n)) return false;
        }
        return true;
    }

    inline ll gcd(ll a, ll b) {
        return b == 0 ? a : gcd(b, a % b);
    }

    inline ll Abs(ll x) {
        return x < 0 ? -x : x;
    }

    inline ll Pollard_rho(ll n) {
        ll s = 0, t = 0, c = rand() % (n - 1) + 1, v = 1, ed = 1;
        while (1) {
            for (int i = 1; i <= ed; i++) {
                t = (mul(t, t, n) + c) % n;
                v = mul(v, Abs(t - s), n);
                if (i % 127 == 0) {
                    ll d = gcd(v, n);
                    if (d > 1) return d;
                }
            }
            ll d = gcd(v, n);
            if (d > 1) return d;
            s = t, v = 1, ed <<= 1;
        }
    }

    void getfactor(ll n) {  //得到有重复的质因子
        if (n <= sz) {
            while (n != 1) fac[cnt++] = p[n], n /= p[n];
            return;
        }
        if (miller(n, 6)) fac[cnt++] = n;
        else {
            ll d = n;
            while (d >= n) d = Pollard_rho(n);
            getfactor(d);
            getfactor(n / d);
        }
    }

    void print(ll x) {   //打印"质因子-个数"
        cnt = 0;
        getfactor(x);
        int k = 1;
        num[0] = 1;
        sort(fac, fac + cnt);
        for (int i = 1; i < cnt; i++) {
            if (fac[i] == fac[i - 1])
                num[k - 1]++;
            else {
                num[k] = 1;
                fac[k++] = fac[i];
            }
        }
        cnt = k;
        for (int i = 0; i < cnt; i++)
            printf("%lld %lld\n", fac[i], num[i]);
    }

    void solve(ll x, ll &tot) {  //进行其他操作
        cnt = 0;
        getfactor(x);
        ll k = 1;
        num[0] = 1;
        sort(fac, fac + cnt);
        for (int i = 1; i < cnt; i++) {
            if (fac[i] == fac[i - 1])
                num[k - 1]++;
            else {
                num[k] = 1;
                fac[k++] = fac[i];
            }
        }
        cnt = tot = k;
    }

} Q;

ll fac[maxn], num[maxn];
ll g, l, res, ansa, ansb, sum, tot;

ll qkp(ll x, ll n) {
    ll ans = 1;
    while (n) {
        if (n & 1) ans *= x;
        x *= x;
        n >>= 1;
    }
    return ans;
}

ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a % b);
}

void dfs(ll a, ll b, ll deep) {
    if (a * g + b * g > sum) return;
    if (deep == tot) {
        if (sum > a * g + b * g) {
            sum = a * g + b * g;
            ansa = a * g, ansb = b * g;
        }
        return;
    }
    dfs(a * fac[deep], b, deep + 1);
    dfs(a, b * fac[deep], deep + 1);
}

int main() {
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    //ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    Q.init(100000);
    while (~scanf("%lld%lld", &g, &l)) {
        if (g == l) {
            printf("%lld %lld\n", g, l);
            continue;
        }
        //Q.solve(g, tot1, fac1, num1);
        //Q.print(l/g);
        res = l / g;
        Q.solve(res, tot);
        memcpy(fac, Q.fac, sizeof Q.fac);
        memcpy(num, Q.num, sizeof Q.num);
        for (int i = 0; i < tot; i++)
            fac[i] = qkp(fac[i], num[i]);
        sum = INF;
        dfs(1LL, 1LL, 0);
        if (ansa > ansb) swap(ansa, ansb);
        printf("%lld %lld\n", ansa, ansb);
    }
    return 0;
}
POJ - 3616是一个题目,题目描述如下: 给定一组区间,每个区间有一个权重,要求选择一些区间,使得这些区间的右端点都小于等于k,并且权重之和最大。请问最大的权重和是多少? 解决这个问题的思路是使用动态规划。首先,将区间按照左端点从小到大进行排序。然后,定义一个dp数组,dp[i]表示右端点小于等于i的所有区间所能得到的最大权重。 接下来,遍历每一个区间,对于每个区间i,将dp[i]初始化为区间i的权重。然后,再遍历i之前的每个区间j,如果区间j的右端点小于等于k,并且区间j的权重加上区间i的权重大于dp[i],则更新dp[i]为dp[j]加上区间i的权重。 最后,遍历整个dp数组,找到最大的权重和,即为所求的答案。 下面是具体的代码实现: ```cpp #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct interval{ int start, end, weight; }; interval intervals[10005]; int dp[10005]; int n, m, k; bool compare(interval a, interval b) { if (a.start == b.start) { return a.end < b.end; } else { return a.start < b.start; } } int main() { while(~scanf("%d %d %d", &n, &m, &k)) { memset(dp, 0, sizeof dp); for (int i = 0; i < m; i++) { scanf("%d %d %d", &intervals[i].start, &intervals[i].end, &intervals[i].weight); } sort(intervals, intervals + m, compare); for (int i = 0; i < m; i++) { dp[i] = intervals[i].weight; for (int j = 0; j < i; j++) { if (intervals[j].end <= k && dp[j] + intervals[i].weight > dp[i]) { dp[i] = dp[j] + intervals[i].weight; } } } int maxWeight = 0; for (int i = 0; i < m; i++) { maxWeight = max(maxWeight, dp[i]); } printf("%d\n", maxWeight); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值