• luogu1072 Hankson的趣味题


    题目大意

    给出数a0, a1, b0, b1,求满足gcd(a0, x)=a1, lcm(b0, x)=b1的x的个数

    解法一

    枚举b1的因数,看看是否满足上述条件。

    怎样枚举因数

    试除法。对于1~sqrt(b1)的所有数i,若其能被b1整除,则i和b1/i便是b1的质因数。

    注意

    • 是sqrt(b1),而不是sqrt(b1)+1。不要擅自主张,因为这样sqrt(b1)~sqrt(b1+1)中的能被b1整除的数就被算重了。
    • 求lcm时,应当为a/gcd(a,b)*b,而不是a*b/gcd(a,b)。因为a*b可能会爆int。
    #include <cstdio>
    #include <cstring>
    #include <cstdarg>
    #include <cmath>
    #include <cassert>
    using namespace std;
    
    const int MAX_P = 45000, MAX_P_CNT = 30000;
    int Primes[MAX_P_CNT];
    int A, B, Gcd, Lcm, AnsCnt, N;
    
    void GetPrime(int *prime, int n)
    {
    	static bool NotPrime[MAX_P];
    	memset(NotPrime, false, sizeof(NotPrime));
    	int primeCnt = 0;
    	for (int i = 2; i <= n; i++)
    	{
    		if (!NotPrime[i])
    			prime[primeCnt++] = i;
    		for (int j = 0; j < primeCnt; j++)
    		{
    			if (prime[j] * i > n)
    				break;
    			NotPrime[prime[j] * i] = true;
    			if (i%prime[j] == 0)
    				break;
    		}
    	}
    }
    
    int GetGcd(int a, int b)
    {
    	return b ? GetGcd(b, a%b) : a;
    }
    
    int GetLcm(int a, int b)
    {
    	return a / GetGcd(a, b) * b;//易忘点:Not a * b / GetGcd(a, b)
    }
    
    void Dfs(int pos, int prod, int curTime)
    {
    	if (pos>=0 && Primes[pos] > N)
    		return;
    	assert(Lcm%prod == 0);
    	if (curTime > 0)
    	{
    		if (GetGcd(prod, A) == Gcd && GetLcm(prod, B) == Lcm)
    			AnsCnt++;
    		int d = Lcm / prod;
    		if (d != prod && GetGcd(d, A) == Gcd && GetLcm(d, B) == Lcm)
    			AnsCnt++;
    	}
    	for (int time = 0; prod <= N && Lcm%prod==0; time++)
    	{
    		Dfs(pos + 1, prod, time);
    		prod *= Primes[pos + 1];
    	}
    }
    
    int main()
    {
    	GetPrime(Primes, MAX_P);
    	int caseCnt;
    	scanf("%d", &caseCnt);
    	while (caseCnt--)
    	{
    		scanf("%d%d%d%d", &A, &Gcd, &B, &Lcm);
    		AnsCnt = 0;
    		N = sqrt(Lcm);//易忘点:Don't plus 1
    		Dfs(-1, 1, 1);
    		printf("%d
    ", AnsCnt);
    	}
    	return 0;
    }
    

    解法二

    每个数都可以用Πp[i]^m[i](p[i]是质数)表示,对于两个数a,b的最大公因数,它每一个p[i]的m[i]是a,b的m[i]中的较小值,最小公倍数是较大值。最终的结果便是每个p[i]计算出的满足较大较小关系的x的取值范围的大小。

    注意

    枚举n的质因数时,可能存在一个质数p>sqrt(n)。此时不要忘了它呀!

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdarg>
    using namespace std;
    
    const int MAX_P = 45000, MAX_P_CNT = 3000;
    int Primes[MAX_P_CNT];
    int TotPrime;
    
    int GetPrime(int *prime, int n)
    {
    	static bool NotPrime[MAX_P];
    	memset(NotPrime, false, sizeof(NotPrime));
    	int primeCnt = 0;
    	for(int i=2; i<=n; i++)
    	{
    		if (!NotPrime[i])
    			prime[primeCnt++] = i;
    		for (int j = 0; j < primeCnt; j++)
    		{
    			if (i*prime[j] > n)
    				break;
    			NotPrime[i*prime[j]] = true;
    			if (i%prime[j] == 0)
    				break;
    		}
    	}
    	return primeCnt;
    }
    
    int GetM(int prime, int &x)
    {
    	int cnt = 0;
    	while (x%prime == 0)
    	{
    		cnt++;
    		x /= prime;
    	}
    	return cnt;
    }
    
    void DoPrime(int prime, int &ans, int &a, int &gcd, int &b, int &lcm)
    {
    	int mA = GetM(prime, a), mGcd = GetM(prime, gcd), mB = GetM(prime, b), mLcm = GetM(prime, lcm);
    	if (mA == mGcd && mB == mLcm && mGcd <= mLcm)
    		ans *= mLcm - mGcd + 1;//x *= prime ^ (mGcd ~ mLcm)
    	else if (mA == mGcd && mB < mLcm && mGcd <= mLcm)
    		ans *= 1;//x *= prime ^ (mLcm)
    	else if (mA > mGcd && mB == mLcm && mGcd <= mLcm)
    		ans *= 1;//x *= prime ^ (mGcd)
    	else if (mA > mGcd && mB < mLcm && mGcd == mLcm)
    		ans *= 1;//x *= (mGcd == mLcm)
    	else
    		ans *= 0;
    }
    
    int Proceed(int a, int gcd, int b, int lcm)
    {
    	int ans = 1, end = max(a, lcm);
    	for (int p = 0; Primes[p] <= end && ans && p<TotPrime; p++)
    		DoPrime(Primes[p], ans, a, gcd, b, lcm);
    	if (a > 1)
    		DoPrime(a, ans, a, gcd, b, lcm);
    	else if (lcm > 1 && lcm != a)
    		DoPrime(lcm, ans, a, gcd, b, lcm);
    	return ans;
    }
    
    int main()
    {
    	TotPrime = GetPrime(Primes, MAX_P);
    	int caseCnt;
    	scanf("%d", &caseCnt);
    	while (caseCnt--)
    	{
    		int a, gcd, b, lcm;
    		scanf("%d%d%d%d", &a, &gcd, &b, &lcm);
    		printf("%d
    ", Proceed(a, gcd, b, lcm));
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    Linux学习笔记21——线程同步的两种方式
    Linux学习笔记20——第一个多线程程序
    Linux学习笔记19——信号2
    Linux学习笔记18——信号1
    Linux学习笔记17——输入输出重定向
    Linux学习笔记16——wait函数
    Linux学习笔记15——GDB 命令详细解释【转】
    Linux学习笔记14——使用fcntl实现文件锁定
    Linux学习笔记13——使用curses函数库
    Linux学习笔记12——Unix中的进程
  • 原文地址:https://www.cnblogs.com/headboy2002/p/8845912.html
Copyright © 2020-2023  润新知