洛谷 P1072 Hankson 的趣味题 || 打质数表的分解质因数

方法就是枚举,根据b0和b1可以大大减小枚举范围,方法类似这个http://blog.csdn.net/hehe_54321/article/details/76021615

将b0和b1都分解质因数。记b0的某一质因数x的指数为a,b1中x的指数为b。如果a>b,那么显然对于这组b0和b1不可能有答案;如果a=b,那么ans中的x的指数可以为0到a的任意一个数;如果a<b,那么ans中x的指数只能为b。

举例:

$$
egin{array}{l|l}
b0=37 & b1=1776 \
hline
37 & =37^1*3^0*2^0 \
ans & =37^x*3^1*2^4 \
1776 & =37^1*3^1*2^4 \
hline
b0=37&b1=1776 \
96 & =3^1*2^5 \
ans & =3^2*2^y\
288 & =3^2*2^5
end{array}
$$

x表示0-1的任何数,y表示0-5的任何数。这样子就可以得出所有可能的ans,然后再验证其与a0的gcd是否是a1即可。

注意:

1.像我这样写,需要特判1,因为对1分解质因数会得到1,对其他数分解都不会出现这个1。

2.曾经写了假的分解质因数,结果T掉了...真的分解质因数(要打质数表)还是要记一下。

  1 %:pragma GCC optimize(2)
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<map>
  6 #include<set>
  7 using namespace std;
  8 typedef int LL;
  9 LL prime[10000];
 10 bool vis[50100];
 11 LL ans0[24],ans1[24];
 12 map<LL,LL> ma;
 13 map<LL,LL>::iterator it;
 14 set<LL>::iterator it2;
 15 set<LL> se;
 16 LL temp[2][2000];
 17 LL size,anss;
 18 LL a0,a1,b0,b1,T;
 19 LL gcd(LL a,LL b)
 20 {
 21     LL t;
 22     while(b!=0)
 23     {
 24         t=a;
 25         a=b;
 26         b=t%b;
 27     }
 28     return a;
 29 }
 30 LL pow2(LL x,LL y)
 31 {
 32     LL base=x,ans=1;
 33     while(y>0)
 34     {
 35         if(y&1)    ans*=base;
 36         base*=base;
 37         y>>=1;
 38     }
 39     return ans;
 40 }
 41 void dprime(LL n,LL ans[])
 42 {
 43     LL i;
 44     LL end=floor(sqrt(n+0.5));
 45     for(i=1;prime[i]<=end;i++)
 46         while(n!=prime[i])
 47         {
 48             if(n%prime[i]==0)
 49             {
 50                 if(ma.count(prime[i])==0)
 51                     ma[prime[i]]=++size;
 52                 ans[ma[prime[i]]]++;
 53                 n/=prime[i];
 54             }
 55             else
 56                 break;
 57         }
 58     if(ma.count(n)==0)
 59         ma[n]=++size;
 60     ans[ma[n]]++;
 61 }
 62 int main()
 63 {
 64     
 65     LL ii,i,j,d,dd,d1,d2;
 66     for(i=2;i<=50000;i++)
 67     {
 68         if(!vis[i])    prime[++prime[0]]=i;
 69         for(j=1;j<=prime[0]&&i*prime[j]<=50000;j++)
 70         {
 71             vis[i*prime[j]]=1;
 72             if(i%prime[j]==0)    break;
 73         }
 74     }
 75     scanf("%d",&T);
 76     while(T--)
 77     {
 78         memset(ans0,0,sizeof(ans0));
 79         memset(ans1,0,sizeof(ans1));
 80         se.clear();anss=0;
 81         ma.clear();size=0;
 82         scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
 83         dprime(b0,ans0);
 84         dprime(b1,ans1);
 85         if(ma.count(1)==1)    ans0[ma[1]]=1,ans1[ma[1]]=1;
 86         ii=0;
 87         memset(temp[0],0,sizeof(temp[0]));
 88         temp[0][0]=1;
 89         temp[0][1]=1;
 90         for(it=ma.begin();it!=ma.end();it++)
 91         {
 92             ii^=1;
 93             memset(temp[ii],0,sizeof(temp[ii]));
 94             d=it->second;
 95             dd=it->first;
 96             d1=ans0[d];
 97             d2=ans1[d];
 98             if(d1>d2)
 99             {
100                 puts("0");
101                 goto xxx;
102             }
103             else if(d1==d2)
104             {
105                 for(i=1;i<=temp[ii^1][0];i++)
106                     for(j=0;j<=d2;j++)
107                         temp[ii][++temp[ii][0]]=temp[ii^1][i]*pow2(dd,j);
108             }
109             else
110             {
111                 for(i=1;i<=temp[ii^1][0];i++)
112                     temp[ii][++temp[ii][0]]=temp[ii^1][i]*pow2(dd,d2);
113             }
114         }
115         for(i=1;i<=temp[ii][0];i++)
116             se.insert(temp[ii][i]);
117         for(it2=se.begin();it2!=se.end();it2++)
118         {
119             if(gcd(*it2,a0)==a1)
120                 anss++;
121         }
122         printf("%d
",anss);
123         xxx:;
124     }
125     return 0;
126 }

假的分解质因数:

void dprime(int n,int ans[])
{
    int i;
    for(i=2;i<=n;i++)
        while(n!=i)
        {
            if(n%i==0)
            {
                if(ma.count(i)==0)
                    ma[i]=++size;
                ans[ma[i]]++;
                n/=i;
            }
            else
                break;
        }
    if(ma.count(n)==0)
        ma[n]=++size;
    ans[ma[n]]++;
}

额外的方法:

设x=a1*a2;a0=a1*a3;x*b2=b1;b0*b3=b1;

则a1*a2*b2=b1

又a1是x和a0的最大公约数,所以a2和a3互质。

又b1是x和b0的最小公倍数,所以b2和b3互质。

所以a2和a0/a1,b2和b1/b0互质。

因为a1*a2*b2=b1

所以a2*b2=b1/a1

因此a2,b2是b1/a1的因子,只需枚举并且判断是否与a3,b3互质即可。

https://www.luogu.org/wiki/show?name=%E9%A2%98%E8%A7%A3+P1072

原文地址:https://www.cnblogs.com/hehe54321/p/7694981.html