(这源自最近完成的编程竞赛)
您将获得两个10 ^ 5个整数的数组,范围为1..10 ^ 7,包括:
int N[100000] = { ... }
int D[100000] = { ... }
想象一下,有理数X是将N的所有元素相乘并除以D的所有元素的结果。
修改两个数组而不更改X的值(并且不指定任何元素超出范围),使得N的乘积和D的乘积没有公因子。
一个天真的解决方案(我认为)会起作用......
for (int i = 0; i < 100000; i++)
for (int j = 0; j < 100000; j++)
{
int k = gcd(N[i], D[j]); // euclids algorithm
N[i] /= k;
D[j] /= k;
}
......但这太慢了。
什么是少于10 ^ 9次操作的解决方案?
答案 0 :(得分:3)
将所有数字分解为1到10 7 。 使用Eratosthenes Sieve的修改,您可以比这更好的可能是创建一个只有最小素因子的数组。n
时间内将所有数字从1到O(n*log n)
分解(我认为它更好,O(n*(log log n)²)
左右){ {1}}空间。
O(n*log log n)
使用该筛子对数字// Not very optimised, one could easily leave out the even numbers, or also the multiples of 3
// to reduce space usage and computation time
int *spf_sieve = malloc((limit+1)*sizeof *spf_sieve);
int root = (int)sqrt(limit);
for(i = 1; i <= limit; ++i) {
spf_sieve[i] = i;
}
for(i = 4; i <= limit; i += 2) {
spf_sieve[i] = 2;
}
for(i = 3; i <= root; i += 2) {
if(spf_sieve[i] == i) {
for(j = i*i, step = 2*i; j <= limit; j += step) {
if (spf_sieve[j] == j) {
spf_sieve[j] = i;
}
}
}
}
进行分解,查找其最小素数因子n > 1
,确定其在p
因子分解中的多重性(通过递归查找或简单地查找)划分直到n
不能均匀地划分剩余的辅因子,这取决于更快的因子)和辅助因子。当辅助因子大于1时,查找下一个主要因子并重复。
创建从素数到整数的地图
浏览两个数组,对于p
中的每个数字,将其因子分解中每个素数的指数添加到地图中的值,对于N
中的数字,减去。
浏览地图,如果素数的指数是正数,则输入D
到数组p^exponent
(如果指数太大,你可能需要将它分成几个指数,并且小值,将几个素数组合成一个条目 - 有664579个质数小于10 7 ,因此阵列中的100,000个时隙可能不足以存储每个具有正确功率的质数),如果指数为负数,对N
数组执行相同操作,如果为0,则忽略该素数。
D
或N
中任何未使用的广告位都会设置为1。
答案 1 :(得分:1)
让我们对N&amp;中的每个元素进行素数分解。 D在O(sqrt(10 ^ 7)* 10 ^ 5)中
N[i]=p1^kn1 * p2^kn2 ...
D[i]=p1^kd1 * p2^kd2 ...
维护2个电源阵列
Power_N[p1]=sum of kn1 for all i's
Power_D[p1]=sum of kd1 for all i's
Divide the N and D by p1^(min(Power_N[p1],Power_D[p2])) in O(10^5) each
答案 2 :(得分:1)
对数组中的每个元素进行因式分解,排序,取消。因子分解是有界大小的整数的恒定时间,排序是n log n,并且取消将是线性的。但是,常数因素可能很大。
如果你试图降低实际执行时间而不是降低渐近复杂度,那么通过手动取消小因子(例如2,3,5和7的幂)来预处理数组可能不会有什么坏处。概率(即病理输入除外),这将大大加速大多数算法,代价是几次线性时间过去。
一种更复杂的方法,即集成上述方法,首先要建立一个最多sqrt(10^7) ~= 3162
的素数列表。根据素数定理,应该有大约3162/ln(3162) ~= 392
个这样的素数。 (事实上,为了节省运行时间,你可以/应该预先计算这个表。)
然后,对于N
中的每个这样的整数,并且对于每个素数,将该整数减少到该素数,直到它不再均匀地分开,并且每次递增该素数的计数。对D
执行相同操作,而是递减。一旦你完成了素数表,当前的int将是非-1,当且仅当它是一个大于3162的素数时。这应该是每个数组中总数的7%左右。你可以将它们保存在一堆或某些东西中。当你继续时,也将它们设置为数组中的那些。
最后,你迭代积极因素并将他们的产品放入N.你可能需要将它分成多个数组插槽,这很好。把负面因素放到D中,你就完成了!
这个运行时间需要一分钟才能完成。希望这是合理的。
答案 3 :(得分:0)
我建议几乎所有内容都已写完
设p =(N中所有元素的乘法)
令q =(D中所有元素的乘法)
X =(P / Q);应始终保持不变
找到p,q的素因子;
通过可能将其功率存储在矩阵a [0](2的幂),a [1](3的幂),a [2](5的幂)等等中。
现在您可以比较矩阵中的值并将较低值的幂降低到零。
例如。 p = 1280 q = 720
对于p a [0] = 8(幂为2)a [1] = 0(幂为3)a [2] = 1(幂为5);
对于q b [0] = 4 b [1] = 2 b [2] = 1;
使索引0,1,2 .......
中的一个/两个(如果两者相等)值/ s为零