减少整数分数算法

时间:2012-09-10 19:14:40

标签: c algorithm math factorization

(这源自最近完成的编程竞赛)

您将获得两个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次操作的解决方案?

4 个答案:

答案 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,则忽略该素数。

DN中任何未使用的广告位都会设置为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为零