200. Hankson的趣味题 DFS枚举约数 试除法枚举所有质因子和它的次数

本文介绍了一种优化算法来解决数学竞赛中的问题,涉及数论和约数枚举。通过筛出质数并仅在D的质因子下枚举,降低时间复杂度,避免超时。代码实现中展示了如何使用深度优先搜索枚举约数,从而提高效率,成功通过测试用例。
摘要由CSDN通过智能技术生成

题目

在这里插入图片描述

题解思路

x肯定是b1的约数,所以从这里入手(我是想不到)。
直接枚举所有约数如果符号上面的条件就可以作为答案。
根号D2e3
这样的话复杂度大概5e4
2e3 大概1亿左右,这样是很有可能超时的。

时间复杂度已经接近了,只要稍微优化一下就行了。

在这里插入图片描述
大概在5e3*2e3 1e7
筛出质数后。
我们直接枚举所有质数,以及它的次数。
我们只在D的质因子下枚举。
这样直接用dfs暴力枚举出它的约数,约数个数(这一步可以减少大量dfs的次数)不会超过1600的。dfs的次数最多1600,所以可以忽略复杂度。
这样就能过了。

参考文章

AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
#include <unordered_map>

using namespace std;

const  int  INF =  0x3f3f3f3f;

bool pr[50100] ;
int prm[50100] ;
int cnt = 1 ;
struct node
{
    int z,s;
};
vector <node>  zs;
long long  a0 ,a1 , b0, b1 ;

int ans = 0 ;

void in()
{
    pr[1] = 1 ;
    for (int i = 2 ; i <= 50000 ; i++ )
    {
        if ( ! pr[i] )
        {
            prm[cnt] = i ;
            cnt++;
            for (int j = i*2 ; j <= 50000 ; j+= i )
            {
                pr[j] = 1 ;
            }
        }
    }
}
void dfs(int p , long long k )
{
    if ( p >= zs.size() )
    {
        if ( __gcd(k , a0) == a1 &&  k*b0/__gcd(k,b0) == b1 )
        {
          //  cout<<k<<"\n";
            ans++;
        }
        return ;
    }
    for (int i = 0 ; i <= zs[p].s ; i++ )
    {
        dfs(p+1,k);
        if ( k*zs[p].z > b1 )
            return ;
        k*=zs[p].z;
    }
}


int main ()
{
    ios::sync_with_stdio(false);
    in();
    int T;
    cin >> T ;
    while( T-- )
    {
        zs.clear();
        ans = 0 ;
        cin >> a0 >> a1 >> b0 >> b1 ;
        int d = b1 ;
        for (int i = 1 ; prm[i] <= d/ prm[i] ; i++ )
        {
            int p = prm[i] ;
            if (  b1 % p == 0 )
            {
                int s = 0;
                while(d%p == 0 )
                {
                    d /= p ;
                    s++;
                }
                zs.push_back({p,s});
            }
        }
        if ( d > 1 )
            zs.push_back({d,1});
        dfs(0,1);
        cout<<ans<<"\n";
    }
    return 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值