// Euler0549_simple.linq // 2016-06-01 #define FORCE_GC #if !LINQPAD using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; #endif // # benching 'Euler0549_simple' ... // // S( 10): 39 0,0 ms // S( 100): 2012 0,0 ms // S( 1000): 136817 0,1 ms // S( 10000): 10125843 1,3 ms // S( 100000): 793183093 16,1 ms // S( 1000000): 64938007616 216,5 ms // S( 10000000): 5494373412573 3.538,4 ms // S(100000000): #45a57e1327a02a 66.756,3 ms // // # benching 'Euler0549_lpf_decomp' ... // // S( 10): 39 0,0 ms // S( 100): 2012 0,0 ms // S( 1000): 136817 0,0 ms // S( 10000): 10125843 0,3 ms // S( 100000): 793183093 1,9 ms // S( 1000000): 64938007616 19,5 ms // S( 10000000): 5494373412573 196,1 ms // S(100000000): #45a57e1327a02a 1.990,3 ms class Euler0549_simple_linq: Euler0549 { static void Main () { bench_and_print(Euler0549_lpf_decomp.s_sum, "Euler0549_lpf_decomp"); bench_and_print(Euler0549_simple.s_sum, "Euler0549_simple"); } } class Euler0549 { public const int EULER_N = 100000000; // computes s(p^e) for p prime public static int s_for_prime_power (int p, int e) { int k = 0; while (e > p) { k += p; e -= p + 1; for (int t = k; (t /= p) % p == 0; ) --e; } return (k + Math.Max(0 , e)) * p; } public delegate long test_func (int n); public static void bench_and_print (test_func f, string name, int lo = 10, int powers_of_ten = 8) { Console.WriteLine("# benching '{0}' ...\n", name); f(2*2*3*3); // get it jitted for (int n = lo, e = 0; e < powers_of_ten; n *= 10, ++e) { Console.Write("S({0,9}): ", n); #if FORCE_GC force_gc(); #endif var t = Stopwatch.StartNew(); var x = f(n); t.Stop(); Console.WriteLine("{0,18} {1,10:N1} ms", n == EULER_N ? spoiler(x) : x.ToString(), t.Elapsed.TotalMilliseconds ); } Console.WriteLine(); } // last hex digits of the MD5 of the text representation public static string spoiler (long n) { var text = ASCIIEncoding.ASCII.GetBytes(n.ToString()); var hash = new System.Security.Cryptography.MD5Cng() .ComputeHash(text) .Select(x => x.ToString("x2")).Aggregate((s,x) => s + x); return "#" + hash.Substring(Math.Max(0, hash.Length - text.Length + 1)); } static void force_gc () { System.Runtime.GCSettings.LargeObjectHeapCompactionMode = System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(9, GCCollectionMode.Forced); } } class Euler0549_lpf_decomp: Euler0549 { public static int[] s; public static long s_sum (int limit) { int small_prime_limit = (int)Math.Sqrt(limit); var small_primes = new List(); int m = 2; s = new int[limit + 1]; for (int half = limit / 2; m <= half; ++m) { if (s[m] == 0) // prime { s[m] = m; if (m <= small_prime_limit) small_primes.Add(m); } int s_m = s[m], threshold = limit / m; foreach (int p in small_primes) { if (p > threshold) // i.e. if (p * m > limit) break; if (m % p != 0) // not a factor of m yet { // p is a new least factor -> s(p) < s(m) -> s(p * m) = s(m) s[p * m] = s_m; } else // p is already a (least) factor of m { int e = 2, q = m; while ((q /= p) % p == 0) ++e; s[p * m] = Math.Max(s_for_prime_power(p, e), s[q]); break; } } } for ( ; m <= limit; ++m) if (s[m] == 0) s[m] = m; long sum = 0; for (int i = 2; i <= limit; ++i) sum += s[i]; return sum; } } class Euler0549_simple: Euler0549 { public static long s_sum (int n) { long result = 0; for (int i = 2; i <= n; ++i) result += s(factorisation(i)); return result; } public static int s (List factors, int lo = 0) { int p = factors[lo], hi = lo; while (++hi < factors.Count && factors[hi] == p) ; int result = s_for_prime_power(p, hi - lo); if (hi < factors.Count) result = Math.Max(result, s(factors, hi)); return result; } static ushort[] g_small_primes = U16.SmallPrimesUpTo(1 << 16, 6542).ToArray(); static List factorisation (int n) { var result = new List(); int sqrt_n = (int)Math.Sqrt(n); foreach (var prime in g_small_primes) { if (prime > sqrt_n) break; if (n % prime == 0) { do result.Add(prime); while ((n /= prime) % prime == 0); sqrt_n = (int)Math.Sqrt(n); } } if (n != 1 || result.Count == 0) result.Add(n); return result; } } class U16 { public static List SmallPrimesUpTo (int n, int initial_allocation_size = 0) { var result = new List(initial_allocation_size); if (n < 2) return result; result.Add(2); // needs to be pulled out of thin air because of the mod 2 wheel if (n < 3) return result; result.Add(3); // needs to be pulled out of thin air because of the mod 3 decoder int sqrt_n_halved = (int)Math.Sqrt(n) >> 1; int max_bit = (n - 1) >> 1; var odd_composite = new bool[max_bit + 1]; for (int i = 5 >> 1; i <= sqrt_n_halved; ++i) if (!odd_composite[i]) for (int p = (i << 1) + 1, j = p * p >> 1; j <= max_bit; j += p) odd_composite[j] = true; for (int i = 5 >> 1, d = 1; i <= max_bit; i += d, d ^= 3) if (!odd_composite[i]) result.Add((ushort)((i << 1) + 1)); return result; } }