C♯の勉強

C♯4.0 で TopCoder の過去問を解きます。

TopCoder SRM596: SparseFactorialDiv2

\(F(n) = n (n - 1^2) (n - 2^2) ... (n - k^2) \) ただし \(k\) は \((n - k^2) > 0\) となる最大の整数とする

「\(F(n) \mod m = 0 \)」が成立することと

「\((n - x^2) \mod m = 0\) かつ \( n > x^2 \) となるような自然数 \( x \) が存在すること」は同値になる。

ここで「\(F(n + m) \mod m = 0 \)」の条件を考えると、同様な手順で

「\((n - x^2) \mod m = 0\) かつ \( n + m > x^2 \) となるような自然数 \( x \) が存在すること」となり、前者の条件には全く違いで出てこない。そして後者の条件についても \( n > x^2 \) から \( n + m > x^2 \) へと緩くなっていることから、
「\(F(n) \mod m = 0 \)」ならば「\(F(n + m) \mod m = 0 \)」ということが言える。

したがって、0 から m-1 までの整数 k についてそれぞれ \(F(i * m + k) \mod m = 0 \)」となるような最小を i を見つければ、 \(F((i + j) * m + k)\)(j は自然数)について全て m で割り切れるため、あとは範囲内のものを数え上げるだけになる。

public class SparseFactorialDiv2 {
    public long solve(long x, long divisor) {
        long ans = 0;
        for (int m = 0; m < divisor; m++) {
            long t = 0;
            bool found = false;
            for (long p = m; p <= x; p += divisor) {
                if (!found) {
                    while (t < divisor && t * t < p) {
                        if (p % divisor == t * t % divisor) {
                            found = true;
                            break;
                        }
                        t++;
                    }
                    if (t >= divisor && !found) break;
                }
                if (found) {
                    // F(p + i * divisor) where i >= 0 are all divisible
                    ans += (x - p) / divisor + 1;
                    break;
                }
            }
        }
        return ans;
    }

    public long getCount(long lo, long hi, long divisor) {
        return solve(hi, divisor) - solve(lo - 1, divisor);
    }
}