题目: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; }