1. 程式人生 > >洛谷1072 Hankson 的趣味題(素數)

洛谷1072 Hankson 的趣味題(素數)

題意

求gcd(a0,x)=a1且lcm(b0,x)=b1中x的解的方案數。

題解

這種gcd的問題一般都要拆成質因數來分析。
線篩出1~sqrt(2e9)中的素數,那麼所有數的質因數一定在其中出現,不然它本身就是一個素數(這個要特判)。
對於質數p,他們的次數分別為ca0,ca1,cb0,cb1。
分析gcd的特點,因為gcd(a0,x)=a1,所以有min(ca0,x)=ca1。具體情況如下:
1、ca0<ca1,無解
2、ca0=ca1,cx>=ca0
3、ca0>ca1,cx=ca1
同理分析lcm,因為lcm(b0,x)=b1,所以max(cb0,x)=cb1。具體分析:
1、cb0>cb1,無解
2、cb0=cb1,cx<cb0
3、cb0<cb1,cx=cb1
結合兩者的情況,會有
1、ca0<cb0 或 cb0>cb1,無解
2、ca0=ca1 且 cb0=cb1,若同時有ca0<=cb0,則cx有cb0-ca0+1個取值方案
3、ca0=ca1 且 cb0<cb1,若同時有ca0<=cb1,則cx有1個取值方案
4、ca0>ca1 且 cb0=cb1,若同時有ca1<=cb0,則cx有1個取值方案
5、ca0>ca1 且 cb0<cb1,若同時有ca1=cb1,則cx有1個取值方案
好了,有了這些就可以打程式碼了,ans等於所有質因數中的取值方案累乘。

程式碼

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2010;
int tot=0,prime[40000];
int v[50000];
void getprime(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(v[i]==0)
        {
            v[i]=i;
            prime[++tot]=i;
        }
        for(int j=1;j<=tot;j++)
        {
            if(prime[j]*i>n || v[i]<prime[j]) break;
            v[prime[j]*i]=prime[j];
        }
    }
}

void get(int &x,int &cnt,int p)
{
    while(x%p==0)
    {
        x/=p;cnt++;
    }
}

int main()
{
    getprime(sqrt(2e9)+10);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int a0,a1,b0,b1;
        scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
        int ca0,ca1,cb0,cb1;
        int ans=1,cnt;
        for(int i=1;i<=tot;i++)
        {
            ca0=ca1=cb0=cb1=0;
            get(a0,ca0,prime[i]);get(a1,ca1,prime[i]);
            get(b0,cb0,prime[i]);get(b1,cb1,prime[i]);
            if(ca0==ca1 && cb0==cb1 && ca0<=cb0) cnt=cb0-ca0+1;
            else if(ca0==ca1 && cb0<cb1 && ca0<=cb1) cnt=1;
            else if(ca0>ca1 && cb0==cb1 && ca1<=cb0) cnt=1;
            else if(ca0>ca1 && cb0<cb1 && ca1==cb1) cnt=1;
            else{ans=0;break;}
            ans*=cnt;
        }
        if(ans!=0)//如果其本身不為1,說明其本身是素數 
        {
recheck:    int p;
            if(a0!=1){p=a0;goto begin;}
            if(a1!=1){p=a1;;goto begin;}
            if(b0!=1){p=b0;goto begin;}
            if(b1!=1){p=b1;goto begin;}
            goto end;
begin:      ca0=ca1=cb0=cb1=0;
            get(a0,ca0,p);get(a1,ca1,p);
            get(b0,cb0,p);get(b1,cb1,p);
            if(ca0==ca1 && cb0==cb1 && ca0<=cb0) cnt=cb0-ca0+1;
            else if(ca0==ca1 && cb0<cb1 && ca0<=cb1) cnt=1;
            else if(ca0>ca1 && cb0==cb1 && ca1<=cb0) cnt=1;
            else if(ca0>ca1 && cb0<cb1 && ca1==cb1) cnt=1;
            else{ans=0;break;}
            ans*=cnt;
            goto recheck;
        }
//      printf("(%lld %lld %lld %lld)\n",a0,a1,b0,b1);
end:    printf("%d\n",ans);
    }
    return 0;
}