TOJ 1537


题目连接:

http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1537


题目类型:

数学 - 数论 - 最大公约数


数据结构:


思路分析:

-----------------------------------------------------------------

形如 X1/X2/X3/..../Xk 式子

利用加括号的方式让它等于一个整数

则可以知道 X1 必为分子, X2 必为分母

另外可以得出, 除X2外, 另其他数字全为分子, 则有最大几率得出整出

最后X2单独作为分母,

只需让分子上的数除尽X2 最后便是整数,

反之不是整数


两种方法

1.-------------------------------------------------------------------------

将X2分解质因子

去除所有的分子,

如果能吧所有的质因子约完,

则能得出整数

2.-------------------------------------------------------------------------

让分子里的所有数都挨个除以它和X2的最大公约数

如果到最后之前能另X2为1

则是YES

否则是NO


证明:

方法1:

因为Xi 是不大于2000000000的数字

所以它的质因子范围可能有2~sqrt(2000000000) =45000  之多,

最大可能个数接近于10 个 (2*3*5....) < 2000000000

所以首先要列举所有可能的质数,

从2开始遍历到45000 找到所有n可能的质因子,

另外要注意的是有可能筛选到 sqrt(n) 的时候 并未列举所有的质因子,

因为有可能有因子 n / 2 > x > sqrt( n )

则那个剩余的数必定是质数 且 只有一个

所以只要列举即可.


方法2:

不进行质因子分解.

直接将X2与各个分子进行相除

分子最大有K-1=9999个

每个分子最大不超过2000000000

设 Xi 与 X2 接近于 2000000000

他们要做最大公约数的运算

运算次数都是在 30以内;



源代码:

方法1:

#include <stdio.h>
#include <iostream>
#include <string>

using namespace std;

bool tese[32005] = { false };
__int64 prime[3500],
		divir[15][2],
		prime_snt = 2;
__int64 arr[10005];

/******************************
		判断素数
*******************************/
void _getprime()
{
	int i, j;
	
	for( i = 2; i < 32000; i ++ )
	{
		if( !tese[i] )
		{
			prime[ prime_snt ++ ] = i;
			
			for( j = i; i * j < 32000; j ++ )
			{
				tese[i * j] = true;
			}	
		}	
	}
}

/******************************
 将字符串根据'/'拆分成整型数组
 参数1:字符串
 参数2:存储分解后的整数
 返回:整数个数
*******************************/
int _split( string s, __int64 * ar )
{
	int i, snt = 1;
	__int64 tmp = 0;

	for( i = 0; i < s.length(); i ++ )
	{
		if( s[i] == '/' )
		{
			if( tmp )
			{
				ar[snt ++] = tmp;
				tmp = 0;
			}
		}
		else
		{
			tmp *= 10;
			tmp += ( s[i] - '0' );
		}
	}

	if( tmp )
	{
		ar[snt ++] = tmp;
		tmp = 0;
	}

	return snt - 1;
}

/*******************************************
 对K2质因子分解
 参数1:整型值
 参数2:用于存储质因子以及个数的二维数组
 返回:不同质因子的个数
********************************************/
__int64 _factor( __int64 r, __int64 dir[15][2] )
{
	__int64 i, snt = 1;

	for( i = 2; i * i <= r && i < prime_snt; i ++ )
	{
		if( r % prime[i] == 0 )
		{
			divir[snt][0] = prime[i];
			divir[snt][1] = 0;

			while( r % prime[i] == 0 )
			{
				r /= prime[i];
				divir[snt][1] ++;
			}

			snt ++;
		}
	}
	
	if( r != 1 )
	{
		divir[snt][0] = r;
		divir[snt][1] = 1;
		snt ++;
	}
	
	return snt - 1;
}

int main()
{
	int i, j;

	_getprime();

	

	int k, m;
	string str;
	
	while( cin >> str )
	{
		k = _split( str, arr );

		if( k == 1 )
		{
			puts( "YES" );
			continue;
		}

		swap( arr[1], arr[2] );

		m = _factor( arr[1], divir );

		for( i = 1; i <= m; i ++ )
		{
			for( j = 2; j <= k; j ++ )
			{
				while( arr[j] % divir[i][0] == 0 && divir[i][1] > 0 )
				{
					arr[j] /= divir[i][0];
					divir[i][1] --;
				}

				if( divir[i][1] == 0 )
				{
					break;
				}
			}
		}

		int rlt = 0;

		for( i = 1; i <= m; i ++ )
		{
			if( divir[i][1] )
			{
				rlt = 1;
				break;
			}
		}

		if( rlt )
		{
			puts( "NO" );
		}
		else
		{
			puts( "YES" );
		}
	}

	return 0;
}



方法2:

#include <stdio.h>
#include <iostream>
#include <string>

using namespace std;

char str[20000];
__int64 arr[10005];

/******************************
 将字符串根据'/'拆分成整型数组
 参数1:字符串
 参数2:存储分解后的整数
 返回:整数个数
*******************************/
int _split( char * s, __int64 * ar )
{
	int i, len = strlen( s ), snt = 1;
	__int64 tmp = 0;

	for( i = 0; i < len; i ++ )
	{
		if( s[i] == '/' )
		{
			if( tmp )
			{
				ar[snt ++] = tmp;
				tmp = 0;
			}
		}
		else
		{
			tmp *= 10;
			tmp += ( s[i] - '0' );
		}
	}

	if( tmp )
	{
		ar[snt ++] = tmp;
		tmp = 0;
	}

	return snt - 1;
}

/************************
	  最大公约数
*************************/

__int64 _gcd( __int64 u ,__int64 v )
{
    int re= u % v; 

    while(re) 
	{
		u = v;
		v = re;
		re = u % v; 
	}

    return v;
}

int main()
{
	int i, j;
	int k, m, rlt = 0;
	
	while( scanf( "%s", str ) != EOF )
	{
		rlt = 0;

		k = _split( str, arr );

		if( k == 1 )
		{
			puts( "YES" );
			continue;
		}

		swap( arr[1], arr[2] );

		for( i = 2; i <= k; i ++ )
		{
			__int64 g = _gcd( arr[i], arr[1] );

			arr[i] /= g;
			arr[1] /= g;

			if( arr[1] == 1 )
			{
				rlt = 1;
			}
		}

		if( !rlt )
		{
			puts( "NO" );
		}
		else
		{
			puts( "YES" );
		}
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值