ALADDIN AND THE FLYING CARPET
https://vjudge.net/contest/70017#problem/C
题目大意:有T组数据,每组数据给两个数n,m,如果n=a*b,求min(a,b)大于等于m这样数对的个数 (a,b)<==>(b,a)
暴力很容易想,直接枚举m~sqrt n看是否能被整除,m>sqrt n 则输出0,但是这样会超时。。(我怎么算着正解和暴力复杂度差不多??)
根据算术基本定理
若n=p1^a1*p2^a2...pn^an则n的因子个数为(a1+1)*(a2+1)...*(an+1),所以我们只要求出小于m这样数对的个数再用总数减就行了,
素数筛的时候会发现如果筛1~1e12范围的全部素数是做不到的,经证明我们只用筛1~1e6 即可:
证明:
假设 n=a*b (a<sqrt n< b <n )如果 b不是质数,则b=c*d (c<sqrt b<d <b)
以此类推,最后大于sqrt n 的因数最多有一个,其余的都小于sqrt n,
也就是说我们分解质因数后剩余的值(temp)判断一下,若temp大于1 说明 temp是大于sqrt n的质数 sum*=2即可,否则说明 全部因数都在1~1e6的范围
#include<bits/stdc++.h> using namespace std; const long long N=1e6+5; long long T,n,ans,tot,m,k,ss[N],sum; bool use[N]; void pd() { use[1]=1; for(int i=2;i<=N-3;i++) { if(use[i]==0) ss[++k]=i; for(int j=1;j<=k&&ss[j]*i<=N-3;j++) { use[i*ss[j]]=1; if(i%ss[j]==0) break; } } } int main() { pd(); scanf("%lld",&T); for(int l=1;l<=T;l++) { ans=0; sum=1; tot=0; scanf("%lld %lld",&n,&m); long long temp=n; for(int i=1;i<=k&&ss[i]<=temp;i++) { tot=0; while(temp%ss[i]==0) { temp/=ss[i]; tot++; } sum*=(tot+1); //printf("###%d %lld %lld\n",i,ss[i],tot); } if(temp>1) sum*=2; //printf("%lld\n",sum); for(int i=1;i<=sqrt(n)&&i<m;i++)//因数小于m的个数 { if(n%i==0) { ans++; } } //printf("%lld\n",sum); printf("Case %d: %lld\n",l,(sum-ans*2)/2); } }
$道路千万条,点赞第一条;阅读不规范,笔者两行泪$