#include <cmath>
#include <vector>
#include <iostream>
#include <tuple>
#include <chrono>
using namespace std;
typedef unsigned int uint;
vector<int> primes({ 2, 3, 5, 7, 11, 13 });
void genPrimes(int max) {
for (int n = 15; n <= max; n += 2) {
auto it = primes.begin() + 1;
for (;;) {
if (it == primes.end()) {
primes.push_back(n);
break;
}
if (n % *it == 0) break;
++it;
}
}
}
static vector<tuple<uint, uint>> factorize(uint n) {
vector<tuple<uint, uint>> result;
for (auto p : primes) {
uint q = n / p, r = n % p;
if (q < p)
break;
if (r != 0)
continue;
uint count = 1;
while (q % p == 0) {
count++;
q /= p;
}
n = q;
result.push_back(make_tuple(p, count));
}
if (n > 1)
result.push_back(make_tuple(n, 1));
return result;
}
static uint factorial_power(uint m, uint p)
{
uint result = 0;
while (m >= p) {
m /= p;
result += m;
}
return result;
}
uint s(uint n)
{
auto factors = factorize(n);
uint lb = 1;
for (auto v: factors)
{
uint p;
uint count;
tie(p, count) = v;
int lb_value = factorial_power(lb, p);
if (lb_value >= count) continue;
int ub = p * count;
if (count < p)
{
lb = ub;
continue;
}
while (lb < ub)
{
int median = lb + (ub - lb) / 2;
int m_value = factorial_power(median, p);
if (m_value < count)
{
lb = median + 1;
}
else
{
ub = median;
}
}
}
return lb;
}
int main()
{
auto t1 = chrono::high_resolution_clock::now();
constexpr int m = 2300000;
constexpr int n = 2400000;
genPrimes(static_cast<int>(sqrt(n)));
int64_t result = 0;
for (auto i = m; i <= n; ++i)
result += s(i);
auto t2 = chrono::high_resolution_clock::now();
cout << result << endl;
cout << "time: " << chrono::duration_cast<chrono::milliseconds>(t2 - t1).count() << "ms" << endl;
}
I2luY2x1ZGUgPGNtYXRoPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRlIDx0dXBsZT4KI2luY2x1ZGUgPGNocm9ubz4KCnVzaW5nIG5hbWVzcGFjZSBzdGQ7CnR5cGVkZWYgdW5zaWduZWQgaW50IHVpbnQ7Cgp2ZWN0b3I8aW50PiBwcmltZXMoeyAyLCAzLCA1LCA3LCAxMSwgMTMgfSk7Cgp2b2lkIGdlblByaW1lcyhpbnQgbWF4KSB7CiAgICBmb3IgKGludCBuID0gMTU7IG4gPD0gbWF4OyBuICs9IDIpIHsKICAgICAgICBhdXRvIGl0ID0gcHJpbWVzLmJlZ2luKCkgKyAxOwogICAgICAgIGZvciAoOzspIHsKICAgICAgICAgICAgaWYgKGl0ID09IHByaW1lcy5lbmQoKSkgewogICAgICAgICAgICAgICAgcHJpbWVzLnB1c2hfYmFjayhuKTsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChuICUgKml0ID09IDApIGJyZWFrOwogICAgICAgICAgICArK2l0OwogICAgICAgIH0KICAgIH0KfQoKCnN0YXRpYyB2ZWN0b3I8dHVwbGU8dWludCwgdWludD4+IGZhY3Rvcml6ZSh1aW50IG4pIHsKICAgIHZlY3Rvcjx0dXBsZTx1aW50LCB1aW50Pj4gcmVzdWx0OwogICAgZm9yIChhdXRvIHAgOiBwcmltZXMpIHsKCQl1aW50IHEgPSBuIC8gcCwgciA9IG4gJSBwOwoJCWlmIChxIDwgcCkKCQkJYnJlYWs7CgkJaWYgKHIgIT0gMCkKCQkJY29udGludWU7CgkJdWludCBjb3VudCA9IDE7CgkJd2hpbGUgKHEgJSBwID09IDApIHsKCQkJY291bnQrKzsKCQkJcSAvPSBwOwoJCX0KCQluID0gcTsKCQlyZXN1bHQucHVzaF9iYWNrKG1ha2VfdHVwbGUocCwgY291bnQpKTsKCX0KCWlmIChuID4gMSkKCQlyZXN1bHQucHVzaF9iYWNrKG1ha2VfdHVwbGUobiwgMSkpOwoJcmV0dXJuIHJlc3VsdDsKfQoKc3RhdGljIHVpbnQgZmFjdG9yaWFsX3Bvd2VyKHVpbnQgbSwgdWludCBwKQp7Cgl1aW50IHJlc3VsdCA9IDA7Cgl3aGlsZSAobSA+PSBwKSB7CgkJbSAvPSBwOwogICAgICAgIHJlc3VsdCArPSBtOwoJfQoJcmV0dXJuIHJlc3VsdDsKfQoKCnVpbnQgcyh1aW50IG4pCnsKICAgIGF1dG8gZmFjdG9ycyA9IGZhY3Rvcml6ZShuKTsKICAgIHVpbnQgbGIgPSAxOwogICAgZm9yIChhdXRvIHY6IGZhY3RvcnMpCiAgICB7CiAgICAgICAgdWludCBwOwogICAgICAgIHVpbnQgY291bnQ7CiAgICAgICAgdGllKHAsIGNvdW50KSA9IHY7CiAgICAgICAgaW50IGxiX3ZhbHVlID0gZmFjdG9yaWFsX3Bvd2VyKGxiLCBwKTsKICAgICAgICBpZiAobGJfdmFsdWUgPj0gY291bnQpIGNvbnRpbnVlOwogICAgICAgIGludCB1YiA9IHAgKiBjb3VudDsKICAgICAgICBpZiAoY291bnQgPCBwKQogICAgICAgIHsKICAgICAgICAgICAgbGIgPSB1YjsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgfQogICAgICAgIHdoaWxlIChsYiA8IHViKQogICAgICAgIHsKICAgICAgICAgICAgaW50IG1lZGlhbiA9IGxiICsgKHViIC0gbGIpIC8gMjsKICAgICAgICAgICAgaW50IG1fdmFsdWUgPSBmYWN0b3JpYWxfcG93ZXIobWVkaWFuLCBwKTsKICAgICAgICAgICAgaWYgKG1fdmFsdWUgPCBjb3VudCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgbGIgPSBtZWRpYW4gKyAxOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgdWIgPSBtZWRpYW47CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICByZXR1cm4gbGI7Cn0KCmludCBtYWluKCkKewogICAgYXV0byB0MSA9IGNocm9ubzo6aGlnaF9yZXNvbHV0aW9uX2Nsb2NrOjpub3coKTsKICAgIGNvbnN0ZXhwciBpbnQgbSA9IDIzMDAwMDA7CiAgICBjb25zdGV4cHIgaW50IG4gPSAyNDAwMDAwOwogICAgZ2VuUHJpbWVzKHN0YXRpY19jYXN0PGludD4oc3FydChuKSkpOwogICAgaW50NjRfdCByZXN1bHQgPSAwOwogICAgZm9yIChhdXRvIGkgPSBtOyBpIDw9IG47ICsraSkKICAgICAgICByZXN1bHQgKz0gcyhpKTsKCiAgICBhdXRvIHQyID0gY2hyb25vOjpoaWdoX3Jlc29sdXRpb25fY2xvY2s6Om5vdygpOwoJY291dCA8PCByZXN1bHQgPDwgZW5kbDsKCWNvdXQgPDwgInRpbWU6ICIgPDwgY2hyb25vOjpkdXJhdGlvbl9jYXN0PGNocm9ubzo6bWlsbGlzZWNvbmRzPih0MiAtIHQxKS5jb3VudCgpIDw8ICJtcyIgPDwgZW5kbDsKfQoK