【NOIP2009】Hankson 的趣味题

题目描述

Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson。现在,刚刚放学回家的 Hankson 正在思考一个有趣的问题。
今天在课堂上,老师讲解了如何求两个正整数 c1 和 c2 的最大公约数和最小公倍数。现在 Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数 a0,a1,b0,b1,设某未知正整数 x 满足:
1. x 和 a0 的最大公约数是 a1;
2. x 和 b0 的最小公倍数是 b1。
Hankson 的“逆问题”就是求出满足条件的正整数 x。但稍加思索之后,他发现这样的x 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的 x 的个数。请你帮助他编程求解这个问题。

解题报告:

写着好玩,好像和网上题解有些不一样
这题可以从c和d下手,考虑c和d的质因子,如果d的某个质因子和c的某个质因子的出现次数相同,那么x就可以取任意个(不超过d)该质因子。
如果c的质因子和d的质因子出现的不相同,那么x含有该因子的次数就确定了,可以直接乘起来。
最后我们把不确定的质因子dfs枚举出现次数,然后暴力判断 \(gcd(x,a0)==a1\) 即可

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=45005;
int a,b,c,d,pri[N],num=0,n=0;bool vis[N];
int li=1;
void getpri(){
   for(int i=2;i<N;i++){
      if(!vis[i])pri[++num]=i;
      for(int j=1;j<=num && pri[j]*i<N;j++){
         vis[pri[j]*i]=true;if(i%pri[j]==0)break;
      }
   }
}
struct node{
   int x,t;
}q[N];
int qm(int x,int k){
   int sum=1;
   while(k){if(k&1)sum*=x;x*=x;k>>=1;}
   return sum;
}
bool check(int y,int goal){
   int x=c,cnt=0;
   while(x%y==0)x/=y,cnt++;
   return cnt!=goal;
}
int ans=0;
int gcd(int x,int y){return x%y?gcd(y,x%y):y;}
void dfs(int dep,int cnt,int tot){
   if(dep==n+1){
      if(gcd(tot,a)==b)ans++;
      return ;
   }
   if(cnt<q[dep].t)dfs(dep,cnt+1,tot*q[dep].x);
   dfs(dep+1,0,tot);
}
void work()
{
   int cnt=0,x;n=0;ans=0;li=1;
   scanf("%d%d%d%d",&a,&b,&c,&d);x=d;
   for(int j=1;j<=num && pri[j]<=x;j++){
      cnt=0;
      while(x%pri[j]==0)x/=pri[j],cnt++;
      if(check(pri[j],cnt))li*=qm(pri[j],cnt);
      else q[++n].x=pri[j],q[n].t=cnt;
   }
   if(x>1){
      if(check(x,1))li*=x;
      else q[++n].x=x,q[n].t=1;
   }
   dfs(1,0,li);
   printf("%d\n",ans);
}

int main()
{
	int T;cin>>T;getpri();
    while(T--)work();
	return 0;
}

posted @ 2017-10-02 22:44  PIPIBoss  阅读(557)  评论(0编辑  收藏  举报