Codeforces Round 828 (Div. 3)E题题解

文章目录

  • [Divisible Numbers (easy version)](https://codeforces.com/contest/1744/problem/E1)
    • 问题建模
    • 问题分析
      • 代码
  • [ Divisible Numbers (hard version)](https://codeforces.com/contest/1744/problem/E2)
    • 问题建模
    • 问题分析
      • 1.根据简单版本分析所求
      • 2.方法1通过因数分解得到a和b的因数,再获得a * b的因数
        • 代码
      • 3.方法2分解a和b的质因数,通过质因数组成a*b的两个因数
        • 代码

Divisible Numbers (easy version)

在这里插入图片描述Codeforces Round 828 (Div. 3)E题题解_第1张图片

问题建模

给定4个数,a,b,c,d,问是否存在两个数x,y, a < x < = c , b < y < = d aa<x<=c,b<y<=d,满足x * y被a * b整除。

问题分析

由于x * y需要包含a * b所有的因数,且x,y还要在一定的范围内,则可以先保证一个数x1在合法位置内,然后通过 a ∗ b / g c d ( a ∗ b , x 1 ) a*b/gcd(a*b,x1) ab/gcd(ab,x1)获得一个包含a * b剩余因子的数s,然后再将其扩大为比d小的数,在检查是否比b大即可。

代码

#include

#define x first
#define y second
#define C(i) str[0][i]!=str[1][i]
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int N =2e5+10, Mod = 998244353, P = 2048;

void solve() {
    LL a,b,c,d;
    cin >>a >>b >>c >>d;
    for(LL i=a+1;i<=c;i++){
        LL s=a*b/(__gcd(a*b,i));
        LL x=d/s*s;
        if(x>b){
            cout <<i <<" " <<x <<"\n";
            return ;
        }
    }

    cout <<-1 <<" " <<-1 <<"\n";
}   


int main() {
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

Divisible Numbers (hard version)

在这里插入图片描述Codeforces Round 828 (Div. 3)E题题解_第2张图片

问题建模

给定4个数,a,b,c,d,问是否存在两个数x,y, a < x < = c , b < y < = d aa<x<=c,b<y<=d,满足x * y被a * b整除。

问题分析

1.根据简单版本分析所求

由于整数的范围扩大,若枚举a+1到c会超时。简单版本中通过 a ∗ b / g c d ( a ∗ b , x 1 ) a*b/gcd(a*b,x1) ab/gcd(ab,x1)获得一个包含a * b剩余因子的数s,实际上是通过枚举x1得到a * b的一个因子,然后获得另一个因子,然后再放大另外一个因子得到符合范围的数。则实际上我们是要获得a * b的因数。

2.方法1通过因数分解得到a和b的因数,再获得a * b的因数

由于a*b的因数是由a的因数乘b的因数得到的,则可以先得到a,b的因数,然后枚举两个因数的乘积从而得到a * b的因数。然后再像简单版本中的做法类似,将两个因数放大到合法范围。由于1e18内的数,最多有103680个因数,1e9内的数最多有1344个因数。则时间复杂度为O( a + b + ( 1344 ) 2 \sqrt{a}+\sqrt{b}+(1344)^2 a +b +(1344)2)

代码

#include

#define x first
#define y second
#define C(i) str[0][i]!=str[1][i]
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int N = 2e5 + 10, Mod = 998244353, P = 2048;

void solve() {
    LL a, b, c, d;
    cin >> a >> b >> c >> d;
    vector<LL> v1, v2;
    ///获得a,b的因数
    for (int i = 1; i <= a / i; i++) {
        if (a % i == 0) {
            v1.push_back(i),v1.push_back(a / i);
        }
    }
    for (int i = 1; i <= b / i; i++) {
        if (b % i == 0) {
            v2.push_back(i),v2.push_back(b / i);
        }
    }

    for (auto i : v1) {
        for (auto j : v2) {
            ///获得a*b的两个因数,然后将其放大到合法的范围
            LL x = i * j,y=a*b/x;
            x*=c/x;
            y*=d/y;
            if(x>a&&y>b){
                cout <<x <<" " <<y <<"\n";
                return ;
            }
        }
    }

    cout << -1 << " " << -1 << "\n";
}


int main() {
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

3.方法2分解a和b的质因数,通过质因数组成a*b的两个因数

由于a*b的因数是由a的部分质数乘b的部分质数得到的,则可以先得到a,b的各个质数,然后通过DFS分配各个质数的数量,从而得到a * b的两个因数。然后再像简单版本中的做法类似,将两个因数放大到合法范围。1e18的数质数组合能产生的因数数量大概为1e5,故不会超时。

代码

#include

#define x first
#define y second
#define C(i) str[0][i]!=str[1][i]
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int N = 2e5 + 10, Mod = 998244353, P = 2048;
LL a,b,c,d;
map<int,int> mp;
vector<PII> primes;

void divide(int n){
    for(int i=2;i<=n/i;i++){
        while(n%i==0)   mp[i]++,n/=i;
    }
    if(n>1) mp[n]++;
}

bool dfs(int u,LL x,LL y){
    if(u==primes.size()){
        x*=c/x;
        y*=d/y;
        if(x>a&&y>b){
            cout <<x <<" " <<y <<"\n";
            return true;
        }else return false;
    }
///分配当前质数的数量到两个因数当中
    int p=primes[u].x,cnt=primes[u].y;
    for(int i=1;i<=cnt;i++) y*=p;
    for(int i=0;i<=cnt;i++){
        if(dfs(u+1,x,y))    return true;
        x*=p,y/=p;
    }
    return false;
}

void solve() {
    mp.clear(),primes.clear();
    cin >>a >>b >>c >>d;
    ///先得到a,b的各个质数数量
    divide(a),divide(b);
    for(auto v:mp)  primes.push_back(v);
    if(!dfs(0,1,1)) cout <<-1 <<" " <<-1 <<'\n';
}


int main() {
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

你可能感兴趣的:(CFdiv3题解,深度优先,算法)