Hankson的趣味題--acwing(快速求一個數的所有約數)
阿新 • • 發佈:2020-12-30
題目: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; }