题意
给定a,b,求[b,a]中有多少对数的乘积为a
思路
唯一分解定理的推论,可以求出正因数的个数,而正因数的值除以2,就是[1,a]中乘积为a的对数,因为限制最小边为b,所以还要减去最小边小于b的情况
代码:
//x的所有因数一定小于根号x,所以可以在根号n时间复杂度下枚举n的因数
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
vector<int>primes;
int isnp[maxn];
int cnt=0;//记录小于b的因数个数
long long int a,b;
void init(int n){
for(int i=2;i<=n;i++){
if(!isnp[i]) primes.push_back(i);
for(auto p : primes){
if(p*i>n) break;
isnp[p*i]=1;
if(i%p==0) break;//这个数肯定之前已经被筛过了,所以可以退出了
}
}
}
int Dvide(long long int tmp){//分解tmp的正因数
int num=1;//分解tmp得到的质因数个数
for(int i=0;i<primes.size()&&primes[i]<=sqrt(tmp);i++){
int x=0;
while(tmp%primes[i]==0){
x++,tmp/=primes[i];
}
num*=(x+1);
//唯一分解定理的推论,正因数个数=(1+a1)(1+a2)(1+a3)....
}
if(tmp>1) num*=2;//如果最后结果大于1,说明tmp是质数,所以应该有两个数
return num;
}
int main(){
int t;
scanf("%d",&t);
init(1e6);
for(int i=1;i<=t;i++){
scanf("%lld%lld",&a,&b);//这里有个常识,因为a是面积,b是两条边中最小的边,所以b不会超过根号a,否则输出0
cnt=0;
if(a<b*b) printf("Case %d: 0\n",i);
else{
int ans=Dvide(a);
ans/=2;
for(int j=1;j<b;j++)//所以这里b的上限是1e6,注意这里很耗时,所以会t,正解不是
if(a%j==0) ans--;//因为题目要求最小边不能小于b,所以去掉约数中有小于b的情况
printf("Case %d: %d\n",i,ans);
}
}
return 0;
}