HDU5974方程化简

题意:

Given two positive integers a and b,find suitable X and Y to meet the conditions:
​ X+Y=a
​ Least Common Multiple (X, Y) =b

Input

Input includes multiple sets of test data.Each test data occupies one line,including two positive integers a(1≤a≤2*104),b(1≤b≤109),and their meanings are shown in the description.Contains most of the 12W test cases.

Output

For each set of input data,output a line of two integers,representing X, Y.If you cannot find such X and Y,output one line of “No Solution”(without quotation).

Sample Input

6 8
798 10780

Sample Output

No Solution
308 490

​ 翻译成汉语,就是给出两个数a,b (a <= 2e4, b <= 1e9),问是否存在x,y,使得x + y = a, x和y的最小公倍数为b?一共有12万组样例!!

思路:

​ 由于有12W组样例,只要每组样例超过1e3几乎就凉了,因此这个题肯定不能暴力。于是我想到了第一种方法:

​ 方法一:先利用素数筛把sqrt(1e9)以内的所有素数筛出来,然后求出b的所有种素因子和每种素因子的个数。

然后dfs每种素因子(每种素因子可以取0~a[i]个),再加上各种剪枝。。。982ms飘过~~

在这里插入图片描述

​ 方法一代码耗时982ms实在是太吓人了,万一现场赛评测机一个不高兴给你慢个20ms你就嗝屁了,然后看到网上正解,一拍脑瓜子。哎,智商压制啊~

​ 方法二:我们设x和y的最大公约数为c,那么x = i ✖️ c,y = j ✖️ c。

​ 由于c是x,y的最大公约数,所以i,j一定互质(要是两者不互质存在公约数的话,x,y的最大公约就为c✖️i和j的公约数,而不是c了,因此i,j一定互质)

​ 那么:

​ a = x + y = (i ✖️ c) + (j✖️c)= (i + j) ✖️ c

​ b = lcm(x, y) = x ✖️ y / gcd(x, y) = x ✖️ y / c = (i ✖️ c ✖️ j ✖️ c) / c = i ✖️j✖️c

​ 由于i,j互质,那么(i + j)和 (i * j)也一定互质。我们可以用反证法证明:

​ 若(i + j),(i✖️j)不互质存在一个素因子t:那么在i✖️j中,t只能是 i的素因子 或 j的素因子(因为i,j互质,不存在公共素因子);又因为i和j必须都存在素因子t才能使得(i + j)存在素因子t(相当于同余定理,若a % t == 0, 则b % t == 0才能使得(a + b)% t == 0),因此和i 存在素因子t 或 j存在素因子t相矛盾,所以(i + j)和(i * j)互质

​ 因此gcd(a, b) = c = gcd (x, y)

​ 因此化简得:

​ x + y = a (一)

​ x✖️y = b ✖️ gcd(x, y) = b ✖️gcd(a, b) (二)

​ a,b已知,因此就相当于解二元一次方程,把方程(一)带入(二)得:

​ x✖️(a - x) = b ✖️gcd(a, b)

=> x^2 - a✖️x + b✖️gcd(a,b) = 0

=> x = (a + sqrt(a^2 - 4✖️b✖️gcd(a,b))) / 2

​ 就可以求出x,y了。这样代码简短,而且耗时只有124ms:

在这里插入图片描述

​ Orz~

代码:

​ 方法一:

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <ctype.h>
#define d int32_t
#define ll int64_t
#define N 32000
#define mem(a) memset(a, 0, sizeof(a))
#define For(i, star, endd) for(d i = star; i <= endd; i++)

bool book[N + 5];
int prime[N + 5];
ll ans[105];
ll ansnum[105];
ll a, b;
bool flag;

//预处理素数
void init() {
    mem(book);
    mem(prime);
    For(i, 2, N) {
        if (!book[i]) {
            prime[++prime[0]] = i;
        }
        For(j, 1, prime[0]) {
            ll t = prime[j] * i;
            if (t > N) break;
            book[t] = 1;
            if (i % prime[j] == 0) break;
        }
    }
}

//求最大公约数
ll gcd (ll y, ll x) {
    ll c = y % x;
    return c == 0? x: gcd(x, c);
}

//枚举不同素数组成的因子可能
void dfs(ll now, ll n, ll val) {
    if (flag) return;
    if (val > a / 2) return;
    if(now == n + 1) {
        if(val * (a - val) / gcd((a - val), val) == b) {
            printf("%lld %lld\n", val, a - val);
            flag = 1;
        }
        return;
    }
    ll res = 1;
    dfs(now + 1, n, val);
    For(i, 1, ansnum[now]) {
        res *= ans[now];
        dfs(now + 1, n, val * res);
    }
}

d main () {
    init();
    while (scanf("%lld%lld", &a, &b) == 2) {
        mem(ansnum);
        ll tot = 0, bb = b;
        flag = 0;
        For(i, 1, prime[0]) {
            if(bb % prime[i] == 0) {
                ans[++tot] = prime[i];
                while(bb % prime[i] == 0) {
                    ansnum[tot]++;
                    bb /= prime[i];
                }
            }
            if (bb == 1) break;
        }
        if(bb != 1) {
            ans[++tot] = bb;
            ansnum[tot] = 1;
        }
        dfs(1, tot, 1);
        if(!flag) {
            printf("No Solution\n");
        }
    }
    return 0;
}

​ 方法二:

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <ctype.h>
#include <math.h>
#include <algorithm>
#define d int32_t
#define ll int64_t
#define mem(a) memset(a, 0, sizeof(a))
#define For(i, star, endd) for(d i = star; i <= endd; i++)
using namespace std;


ll gcd (ll y, ll x) {
    ll c = y % x;
    return c == 0? x: gcd(x, c);
}


d main () {
    ll a, b;
    while (scanf("%lld%lld", &a, &b) == 2) {
        ll c = gcd(max(a, b), min(a, b));
        double x = (sqrt(a * a - 4 * b * c) + a) / 2;
        if (x == (ll)x) {
            ll t = (ll)x;
            printf("%lld %lld\n", min(t, a - t), max(t, a - t));
        } else {
            printf("No Solution\n");
        }
    }
    return 0;
}

转载请注明出处!!!

如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值