題目連接:
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;
}