【问题标题】:Sum of series: 1^1 + 2^2 + 3^3 + ... + n^n (mod m)系列之和:1^1 + 2^2 + 3^3 + ... + n^n (mod m)
【发布时间】:2010-12-02 22:42:24
【问题描述】:

谁能给我一个关于大 n(比如 10^10)的有效算法的想法,以找到上述系列的总和?

Mycode 在 n=100000 和 m=200000 时被淘汰

#include<stdio.h>

int main() {
    int n,m,i,j,sum,t;
    scanf("%d%d",&n,&m);
    sum=0;
    for(i=1;i<=n;i++) {
        t=1;
        for(j=1;j<=i;j++)
            t=((long long)t*i)%m;
        sum=(sum+t)%m;
    }
    printf("%d\n",sum);

}

【问题讨论】:

  • Aviator:高效算法通常独立于语言。这是 Java 还是 C 并不重要(运行时可能是线性因素除外)。
  • @Johannes:我明白了。我想建议 BigInteger。这就是为什么问
  • 你说你想要大 n (10^10) 的东西快,但你没有说 m 是否同样大,或者它是否保持在 200k 左右。这可能很重要,因为如果 m 很小,那么您可以尝试预先计算/缓存一些术语。如果您已经知道所有 a 小于 m 的 a^m 和 a^a,那么当您计算 (m+2)^(m+2) 时,它就是 2^(m+2) = 2^m* 2^2。然后 (m+3)^(m+3) = 3^m*3^3 依此类推。您可能可以安排一些事情,以便您始终按顺序访问存储的值,不确定。
  • 考虑一下,在计算 2m+1 ... 3m-1 项时,您可能还想缓存 1^2m ... (m-1)^2m .然后使用这些值计算 1^3m ... (m-1)^3m,并将存储的值替换为用于计算 1^4m ... (m-1)^4m 的新值。如果不编写代码,我不知道这是否真的会比 Mehrdad 的 solutino 更快,但除非我错过了致命的东西,否则它是 O(n) 而不是 O(n log n)。显然需要 O(m) 内存。
  • 哦,使用 Mehrdad 的代码计算缓存值需要 O(m log m) 时间。因此,如果 m 与 n 一起增长,它可能根本没有帮助,但如果 m 是有界的,它可能是一种改进。

标签: algorithm series


【解决方案1】:

我最近遇到了类似的问题:我的'n'是1435,'m'是10^10。这是我的解决方案(C#):

ulong n = 1435, s = 0, mod = 0;
mod = ulong.Parse(Math.Pow(10, 10).ToString());
for (ulong i = 1; i <= n; 
{
     ulong summand = i;
     for (ulong j = 2; j <= i; j++)
     {
         summand *= i;
         summand = summand % mod;
     }
     s += summand;
     s = s % mod;
}

末尾的 's' 等于所需的数字。

【讨论】:

    【解决方案2】:

    我不能加评论,但是对于中国剩余定理,请参阅http://mathworld.wolfram.com/ChineseRemainderTheorem.html公式(4)-(6)。

    【讨论】:

      【解决方案3】:

      你会在这里被杀吗:

      for(j=1;j<=i;j++)
          t=((long long)t*i)%m;
      

      指数 mod m 可以使用平方和方法来实现。

      n = 10000;
      m = 20000;
      sqr = n;
      bit = n;
      sum = 0;
      
      while(bit > 0)
      {
          if(bit % 2 == 1)
          {
              sum += sqr;
          }
          sqr = (sqr * sqr) % m;
          bit >>= 2;
      }
      

      【讨论】:

        【解决方案4】:

        我认为您可以使用欧拉定理来避免某些指数,例如 phi(200000)=80000。中国剩余定理也可能有所帮助,因为它减少了模数。

        【讨论】:

        • 这确实敲响了一些警钟,但恐怕你必须解释一下。此外,iirc,计算 phi 也并非易事。
        • 您只需要计算一次 phi。欧拉定理说,如果 (a,b)=1,a^phi(b)=1 mod b。然后您可以将 a^c mod b 简化为 a^c' mod b where c' 的形式
        • Jaska:这里无关紧要。如果(a,b) != 1怎么办?
        • 提示 - 尝试编辑您的答案。精心制作的。描述并解释你建议的算法。尝试发布一些代码。链接到维基百科。还有,中国剩余定理不是用在方程组上的吗?
        • 欧拉定理和中国提醒定理很容易查到,它们在这里(结合在一起)完全相关——使用欧拉定理计算以 m 为单位的每个素数的和模,并使用 CRT 来计算把它们放在一起。
        【解决方案5】:

        两个音符:

        (a + b + c) % m
        

        等价于

        (a % m + b % m + c % m) % m 
        

        (a * b * c) % m
        

        等价于

        ((a % m) * (b % m) * (c % m)) % m
        

        因此,您可以使用 O(log p) 中的递归函数计算每个项:

        int expmod(int n, int p, int m) {
           if (p == 0) return 1;
           int nm = n % m;
           long long r = expmod(nm, p / 2, m);
           r = (r * r) % m;
           if (p % 2 == 0) return r;
           return (r * nm) % m;
        }
        

        然后使用 for 循环对元素求和:

        long long r = 0;
        for (int i = 1; i <= n; ++i)
            r = (r + expmod(i, i, m)) % m;
        

        这个算法是O(n log n)。

        【讨论】:

        • 对于小数字,我也在做同样的事情。但它正在被杀死 n = 1000000 和 m =200000 。我已经包含了代码
        • 我相信你在这些等式中还需要一个'mod':'(a % m + b % m + c % m) % m'和'(a % m) * (b % m) * (c % m) % m'。
        • Groo:是的,在代码中做到了,在方程式中遗漏了。谢谢。固定。
        • @rahul:你的内部 j 循环在 O(i) 中运行。 Mehrdad 的函数在 O(log i) 中运行。通过调用 Mehrdad 的函数来替换您的内部循环,您将获得很大的加速。
        • @rahul。在 n=1000 和 m=2000 的情况下,结果 1000^1000%2000 到 (1000^2%2000)^500%2000。
        【解决方案6】:

        你可以看看我对this post 的回答。那里的实现有点错误,但想法就在那里。关键策略是找到 x 使得 n^(x-1)m 并反复减少 n^n%m 到 (n^x%m)^(n/x)*n^( n%x)%m。我相信这个策略是有效的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-01-10
          • 2012-07-30
          • 1970-01-01
          • 2011-01-29
          • 1970-01-01
          • 2019-05-15
          相关资源
          最近更新 更多