約数でニムをやる。
しかし、ニムに関してより約数を求めるところでつまずく。
区間篩なるモノがあるそうなので、それを模倣してある区間の約数を計算した。ありがとうスパソ。
class TheDivisionGame { public: long long countWinningIntervals(int L, int R) { const int B = R - L + 1; const int N = 100000; static bool prime[N]; fill(prime, prime + N, true); prime[0] = prime[1] = false; for (int i = 2; i * i < N; ++i) { if (!prime[i]) continue; for (int j = i * i; i * j < N; j += i) { prime[j] = false; } } static lli p[N], size = 0; for (int i = 0; i < N; ++i) { if (prime[i]) p[size++] = i; } const int M = 1000000 + 10; static int f[M]; fill(f, f + M, 0); static int num[M]; for (int i = 0; i < M; ++i) { num[i] = i + L; } for (int i = 0; i < size; ++i) { unless (p[i] * p[i] <= R) break; int j; if (p[i] >= L) j = p[i] * p[i]; else if (L % p[i] == 0) j = L; else j = L - (L % p[i]) + p[i]; for (; j <= R; j += p[i]) { while (num[j - L] % p[i] == 0) { num[j - L] /= p[i]; ++f[j - L]; } } } for (int i = 0; i < M; ++i) { if (num[i] != 1) ++f[i]; } const int F = 100; static int cnt[F]; fill(cnt, cnt + F, 0); int nim = 0; for (int i = 0; i < B; ++i) { nim ^= f[i]; ++cnt[nim]; } lli ret = (lli)B * (lli)(B + 1) / 2; ret -= cnt[0]; for (int i = 0; i < F; ++i) { ret -= cnt[i] * (cnt[i] - 1) / 2; } return ret; } };