2009-10-01 3 views
8

Может ли кто-нибудь дать мне представление об эффективном алгоритме для больших n (например, 10^10) найти сумму вышеуказанных серий?Сумма ряда: 1^1 + 2^2 + 3^3 + ... + n^n (mod m)

Mycode становится klilled при п = 100000 т = 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); 

} 
+0

можно использовать java? – vpram86

+10

Aviator: Эффективные алгоритмы обычно не зависят от языка. Не имеет значения, является ли это Java или C (за исключением, возможно, линейного фактора во время выполнения). – Joey

+0

@ Джоханнес: Я понимаю. Я думал о том, что предлагаю BigInteger. Thats why ask – vpram86

ответ

22

Два примечания:

(a + b + c) % m 

эквивалентно

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

и

(a * b * c) % m 

эквивалентно

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

В результате, можно вычислить каждый член с помощью рекурсивной функции в O (журнал р):

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).

+0

Для небольших чисел я делаю то же самое. Но его убивают за n = 1000000 и m = 200000. Я включил код – 2009-10-01 10:01:13

+3

Я считаю, что в этих уравнениях вам нужен еще один «mod»: «(a% m + b% m + c% m)% m 'и' (a% m) * (b% m) * (c% m)% m '. – Groo

+0

Groo: Да, сделал это в коде, пропущен в уравнениях. Благодарю. Исправлена. –

3

Возможно, вы найдете мой ответ на вопрос this post. Реализация там немного глючит, но идея есть. Ключевой стратегией является найти x, для которого n^(x-1) < m и n^x > m и несколько раз уменьшать n^n% m до (n^x% m)^(n/x) * n^п% х)% м. Я уверен, что эта стратегия работает.

5

Я думаю, вы можете использовать теорему Эйлера, чтобы избежать некоторой экспоненты, так как phi (200000) = 80000. Теорема о китайском остатке может также помочь, поскольку она уменьшает модулю.

+0

Это действительно звонит, но я боюсь, вам придется объяснять. Кроме того, iirc, вычисление phi не является тривиальным. – Kobi

+2

Вам нужно вычислить phi только один раз. Теорема Эйлера гласит, что a^phi (b) = 1 mod b, если (a, b) = 1. Тогда вы можете упростить a^c mod b до формы a^c 'mod b, где c' 2009-10-01 10:35:53

+0

Jaska: Здесь неважно. Что делать, если '(a, b)! = 1'? –

0

Вы убитые здесь:

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

Exponentials тойт может быть реализован с использованием методы суммы квадратов.

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; 
} 
1

Недавно я столкнулся с похожим вопросом: my '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' равен требуемому номеру.

Смежные вопросы