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);
    }
}

 

posted @ 2020-03-20 18:09  Sakura_Momoko  阅读(161)  评论(0编辑  收藏  举报