NOIP2009 Hankson的趣味题

传送门

这道题感觉很难想……毕竟数论题好像想到的话基本就没什么事了。

我们要求的数是x,显然可以先设x = p*a1,b1 = t*x,那么b1 = p * t * a1.设s = t * p。

之后我们通过最大公约数和最小公倍数的性质可以先得到,gcd(a0/a1,p) = 1,因为如果二者还有大于1的公约数的话,那么应该存在一个比a1还大的gcd,不成立。同理,我们也可以得到gcd(b1/b0,t) = 1,如果还有大于1的公约数,那么应该存在一个比b1还小的lcm。

这个时候我们已经有暴力的方法了,就是通过枚举s的每一个因子,带入上面两个式子判断是否互质,之后就能计算出合法的x。不过这样的话,会超时,我们考虑进一步优化。

重新观察上面两个式子,因为gcd(b1/b0,s/p) = 1,令m=b1/b0,所以s/p,m必然不存在相同的质因子,我们可以先把s和m相同的质因子筛掉得到新的数l,之后就可以保证s/p必然是l的一个因子。

设a0/a1 = n,那么gcd(n,p) = 1,s/p是l的因子,那么必然p可以表示成r*s/l,那么gcd(r,n) = 1.所以我们只需要把l和n相同的质因子全部筛掉,那么剩下的一个数q的所有因子必然都是合法的了,直接枚举进行计算即可。

注意要特判掉一些不合法情况,分别是n,m,s不为整数和gcd(s/l,n) != 1.因为如果出现这种情况的话,(p,n)必然不为1.

看一下代码。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 20005;
const int N = 10000005;
const int mod = 13;
 
ll read()
{
   ll ans = 0,op = 1;
   char ch = getchar();
   while(ch < '0' || ch > '9')
   {
      if(ch == '-') op = -1;
      ch = getchar();
   }
   while(ch >='0' && ch <= '9')
   {
      ans *= 10;
      ans += ch - '0';
      ch = getchar();
   }
   return ans * op; 
}

int T,a0,a1,b0,b1,n,m,s;

int gcd(int a,int b)
{
   return b ? gcd(b,a%b) : a;
}

int work(int a,int b)
{
   int k = sqrt(b);
   rep(i,2,k)
   {
      if(!(b % i)) while(!(a % i)) a /= i;
      while(!(b % i)) b /= i;
   }
   if(b != 1) while(!(a % b)) a /= b;
   return a;
}

int main()
{
   T = read();
   while(T--)
   {
      a0 = read(),a1 = read(),b0 = read(),b1 = read();
      if(a0 % a1 | b1 % b0 | b1 % a1)
      {
     printf("0\n");
     continue;
      }
      m = a0 / a1,n = b1 / b0,s = b1 / a1;
      int l = work(s,n);
      if(gcd(max(s/l,m),min(s/l,m)) != 1)
      {
     printf("0\n");
     continue;
      }
      int g = work(l,m),cnt = 0,k = sqrt(g);
      rep(i,1,k) if(!(g % i)) cnt += (i == g / i) ? 1 : 2;
      printf("%d\n",cnt);
   }
   return 0;
}

 

posted @ 2018-10-29 22:18  CaptainLi  阅读(208)  评论(0编辑  收藏  举报