C#:49,000(980,000,000 / 20,000)
/codegolf//a/26800「ハワードのコード」。
ただし、修正されたphi値は、奇数の整数に対して計算されます。
using System;
using sw = System.Diagnostics.Stopwatch;
class Program
{
static void Main()
{
sw sw = sw.StartNew();
Console.Write(sumPhi(980000000) + " " + sw.Elapsed);
sw.Stop(); Console.Read();
}
static long sumPhi(int n) // sum phi[i] , 1 <= i <= n
{
long s = 0; int[] phi;
if (n < 1) return 0; phi = buildPhi(n + 1);
for (int i = 1; i <= n; i++) s += getPhi(i, phi);
return s;
}
static int getPhi(int i, int[] phi)
{
if ((i & 1) > 0) return phi[i >> 1];
if ((i & 3) > 0) return phi[i >> 2];
int z = ntz(i); return phi[i >> z >> 1] << z - 1;
}
static int[] buildPhi(int n) // phi[i >> 1] , i odd , i < n
{
int i, j, y, x, q, r, f; int[] phi;
if (n < 2) return new int[] { 0 };
phi = new int[n / 2]; phi[0] = 1;
for (j = 2, i = 3; i < n; i *= 3, j *= 3) phi[i >> 1] = j;
for (x = 4, i = 5; i <= n >> 1; i += x ^= 6)
{
if (phi[i >> 1] > 0) continue; phi[i >> 1] = i ^ 1;
for (j = 3, y = 3 * i; y < n; y += i << 1, j += 2)
{
if (phi[j >> 1] == 0) continue; q = j; f = i ^ 1;
while ((r = q) == i * (q /= i)) f *= i;
phi[y >> 1] = f * phi[r >> 1];
}
}
for (; i < n; i += x ^= 6) // primes > n / 2
if (phi[i >> 1] == 0)
phi[i >> 1] = i ^ 1;
return phi;
}
static int ntz(int i) // number of trailing zeros
{
int z = 1;
if ((i & 0xffff) == 0) { z += 16; i >>= 16; }
if ((i & 0x00ff) == 0) { z += 08; i >>= 08; }
if ((i & 0x000f) == 0) { z += 04; i >>= 04; }
if ((i & 0x0003) == 0) { z += 02; i >>= 02; }
return z - (i & 1);
}
}
新しいスコア:61,000(1,220,000,000 / 20,000)
「App.config」に「gcAllowVeryLargeObjects enabled = true」を追加する必要がありました。
static long sumPhi(int n)
{
int i1, i2, i3, i4, z; long s1, s2, s3, s4; int[] phi;
if (n < 1) return 0; phi = buildPhi(n + 1); n -= 4; z = 2;
i1 = 1; i2 = 2; i3 = 3; i4 = 4; s1 = s2 = s3 = s4 = 0;
if (n > 0)
for (; ; )
{
s1 += phi[i1 >> 1];
s2 += phi[i2 >> 2];
s3 += phi[i3 >> 1];
s4 += phi[i4 >> z >> 1] << z - 1;
i1 += 4; i2 += 4; i3 += 4; i4 += 4;
n -= 4; if (n < 0) break;
if (z == 2)
{
z = 3; i4 >>= 3;
while ((i4 & 3) == 0) { i4 >>= 2; z += 2; }
z += i4 & 1 ^ 1;
i4 = i3 + 1;
}
else z = 2;
}
if (n > -4) s1 += phi[i1 >> 1];
if (n > -3) s2 += phi[i2 >> 2];
if (n > -2) s3 += phi[i3 >> 1];
if (n > -1) s4 += phi[i4 >> z >> 1] << z - 1;
return s1 + s2 + s3 + s4;
}
static int[] buildPhi(int n)
{
int i, j, y, x, q0, q1, f; int[] phi;
if (n < 2) return new int[] { 0 };
phi = new int[n / 2]; phi[0] = 1;
for (uint u = 2, v = 3; v < n; v *= 3, u *= 3) phi[v >> 1] = (int)u;
for (x = 4, i = 5; i <= n >> 1; i += x ^= 6)
{
if (phi[i >> 1] > 0) continue; phi[i >> 1] = i ^ 1;
for (j = 3, y = 3 * i; y < n; y += i << 1, j += 2)
{
if (phi[j >> 1] == 0) continue; q0 = j; f = i ^ 1;
while ((q1 = q0) == i * (q0 /= i)) f *= i;
phi[y >> 1] = f * phi[q1 >> 1];
}
}
for (; i < n; i += x ^= 6)
if (phi[i >> 1] == 0)
phi[i >> 1] = i ^ 1;
return phi;
}