题目连接:
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;
}