模数为

时间:2015-09-22 09:50:03

标签: algorithm math

我最近想到了以下问题,我很惊讶似乎没有人提出这个问题:

给定一个字符串,它存在多少个不同的排列,模1000000007

我知道公式formula,其中N是字符串的长度,A1A2AK是每个字符的计数(考虑大小为K的字母表)。因此,字符串toffee会有180个不同的排列。

但是当N非常大时(例如100000),这不再有效,因为计算Nfactorial将超出 long long int的范围,使用BigIntegers会太慢。有没有办法在NNlogN时间计算这个?

如果我将1中的阶乘预处理到N,并且我的“字符串”以长度K的数组形式出现,其中每个元素包含每个字母的数量,是否可以在KKlogK时间计算它?

感谢您对此有任何帮助:)

4 个答案:

答案 0 :(得分:6)

诀窍是要注意p = 10^9 + 7是素数。因此,我们可以使用乘法逆和Fermat's little theorem来将公式中的除法转换为乘法的乘法:

n! / (a1!*...*ak!) = 

n! * a1!^(p - 2) * ... * ak!^(p - 2) (mod p)

这将是您的公式mod p,没有分区和简单的实现(只需使用模块exponentiation by squaring)。

复杂性将为O(k log p + n),因为我们有O(k)个乘法,并且对于每个乘法,O(log p)取幂,我们还必须计算n!和每个的阶乘计数。

这比取消分数中的因子更容易实现。

答案 1 :(得分:2)

字符串的不同排列数总是整数,尽管是除法的结果。那是因为分母的因素基本上“淘汰”了分子的一些因素。所以你可以将除法作为后因子运算来消除,而是将你已经与分母因子相匹配的因子分解出来。

一旦你删除了除法,你只需要进行模乘,这很简单。

答案 2 :(得分:0)

如果N不是巨大的(也就是说,它足够小,可以使用像Eratosthenes的Sieve那样筛选它),你可以用N!来计算text=[text stringByAppendingString:@" "]; 的素数因子分解。筛子的修改版本。

然后你可以使用素数因子分解来计算除法,取消除法两边存在的因子。

虽然这并没有考虑到你希望结果模数为素数(存在更好的解决方案)这一事实,但在一般情况下可能有用。

答案 3 :(得分:0)

是..存在解决方案。您可以阅读有关模数乘法逆算法的信息。 This

由于答案是使用模数1000000007(也是素数),您可以尝试使用Fermat's little theorem来解决此问题。如果模数为 mod 复杂度为O(N + K * log(mod))。