1. 程式人生 > 實用技巧 >Hankson的趣味題--acwing(快速求一個數的所有約數)

Hankson的趣味題--acwing(快速求一個數的所有約數)

題目:https://www.acwing.com/problem/content/202/可能需要報名課程才能做。

題意:給a,b,c,d四個數,範圍是1–2e9,求x和a的最大公約數是b,x和c的最小公倍數是d,滿足條件的x有多少個。首先輸入一個n,代表n組資料,n的範圍是1-2000

題解:這個題其實就找d的所有約數,然後列舉每一個約數就行,int範圍內數量最大的約數是1600,所以列舉不多,難的是求d的所有約數,因為有2000的輸入,如果直接暴力求根下n的複雜度,如果給1s時間複雜度是可以過的,但題目給的是0.3s,所以不能暴力求。
較快速度求所有約數:可以先把d的所有質因數求出來,然後dfs暴力搜一下質因數的所有方案,時間複雜度比暴力求快10倍,就可以過了。

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=1e5+10;
int prime[N+10],vis[N+10];
int cnt;
struct node     //記錄所有的質因數
{
    int p,s;  //p記錄質數,s記錄個數
} a[20];     
int node_cnt;  //記錄有多少中質數
int arr[2000];  //存約數
int tol;       //記錄有多少個約數
void init(int n)   //線性篩打素數表
{
    cnt=0;
    vis[0]=vis[1]=1;
    for(int i=2; i<=n; i++)
    {
        if(vis[i]==0)prime[cnt++]=i;
        for(int j=0; prime[j]*i<=n; j++)
        {
            vis[prime[j]*i]=1;
            if(i%prime[j]==0)break;
        }
    }
}
void dfs(int u,int data)  //dfs暴力找所有素數匹配方案,求出約數個數
{
    if(u==node_cnt)  //u==node_cnt說明後面已經沒有質數了,記錄下這個時候的data,
    {
        arr[tol++]=data;
        return ;
    }
    for(int i=0; i<=a[u].s; i++)  //從0開始迴圈個數
    { 
        dfs(u+1,data); //i=0的時候代表這個素數沒有×
        data=data*a[u].p; //放在下邊,i=1的時候,data正好乘素數一次
    }
    return ;
}
int main()
{
    init(N-9);
    int aa,b,c,d;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&aa,&b,&c,&d);
        node_cnt=0,tol=0;  //每次清空
        int t=d;
        for(int i=0; prime[i]*prime[i]<=d&&i<cnt; i++)  //分解質因數
        {
            int s=0;
            int p=prime[i];
            while(d%p==0)
            {
                s++;
                d=d/p;
            }
            if(s>0)
            {
                a[node_cnt].p=p;
                a[node_cnt++].s=s;
            }
        }
        if(d>1)  //如果還有保留,說明剩下的這個質數很大,也要加入
        {
            a[node_cnt++]= {d,1};
        }
        dfs(0,1);  //暴力搜尋方案
        int sum=0;
        for(int i=0; i<tol; i++)  //遍歷每一個約數
        {
            int data=arr[i];
            if(__gcd(data,aa)==b&&((ll)c*data)/__gcd(c,data)==t)sum++;
        }
        printf("%d\n",sum);
    }
    return 0;
}