SPOJ – 30919: GCDS – Sabbir and gcd problem 题解
这是一道数论题。
思路
因为要求找到的整数 x 是一个互质于 a_i 的数,所以很显然 x 为质数的时候最优。
根据互质的一些性质,a_i 和 x 没有共同的质因数,所以可以标记所有 a_i (1\le i\le n) 的质因数,然后选取最小的未被标记的质数。
举个例子:
\rm{a = \tt{[11, 45, 14, 19, 81]}}
标记如下
故选择13作为 x。
看到这里,就滚去写代码罢!
\raisebox{-500px}{}
如果你真的按照这篇文章这么做的话,你多半会:
如果没T当我没说,拜谢
优化
暴力的思路是暴力因式分解,但是这样做有十分甚至九分的可能会超时。那怎么优化呢?
可以维护一个数组 \tt mz,\tt mz[\rm{i}\tt] 代表 i 的最小质因数,这样就可以避免每次标记都要遍历半天的问题。
怎么维护呢?
显然当 i 是质数时,\tt mz[\rm{i}\tt] = \rm i。当 i 不是质数的时候,那么 i 必然可以拆分成 p\times j;根据线性筛的原理,当筛到 p 的时候,p\times j 将会被 p 标记。因此,只需要在线性筛中加入一行:
mz[i * pm_list[j]] = pm_list[j];
就可以达到相应效果。
总的线性筛代码如下:
void make_prime_list(int n)
{
int i, j;
is_prime[1] = 0;
for (i = 2; i <= n; i++) {
if (is_prime[i] == 0) pm_list[++pm_count] = i, mz[pm_list[pm_count]] = i;
for (j = 1; j <= pm_count && i * pm_list[j] <= n; j++) {
is_prime[i * pm_list[j]] = 1;
mz[i * pm_list[j]] = pm_list[j];
if (i % pm_list[j] == 0) break;
}
}
}
主函数核心部分代码:
while (a > 1) {
vs[mz[a]] = 1;
a /= mz[a];
}