Cod sursa(job #2703698)
Utilizator | Data | 9 februarie 2021 00:32:09 | |
---|---|---|---|
Problema | Mins | Scor | 80 |
Compilator | cpp-64 | Status | done |
Runda | Arhiva de probleme | Marime | 17.77 kb |
#include <fstream>
#include <cstdint>
#include <cstddef>
#include <vector>
#include <algorithm>
#include <stdexcept>
typedef std::size_t size_t;
typedef std::uint32_t uint32_t;
typedef std::uint64_t uint64_t;
int main (void);
void demo (void);
uint64_t solve(size_t c, size_t d);
void scan_distinct_prime_factors ( size_t q
, uint32_t * prime_factor
, uint32_t * prime_factors
, size_t & h
);
uint32_t count__non_coprimes ( uint32_t const * prime_factors
, size_t const h
, uint32_t * prime
, int32_t * product
, uint32_t const b
);
int main (void) {
int status = 17;
try {
demo();
status = 0; }
catch ( ... ) {
status = 5; }
return status;
}
void demo (void) {
std::ifstream is("mins.in");
size_t c = 0;
size_t d = 0;
is >> c >> d;
if (1 <= c && c <= 1000000 && 1 <= d && d <= 1000000) {} else {
throw std::invalid_argument("One of c and d is a bad apple."); }
uint64_t const answer = solve(c, d);
std::ofstream os("mins.out");
os << answer << '\n';
}
uint64_t solve(size_t c, size_t d) {
/// Determines the # of y/x fractions, 1 ≤ x ≤ c − 1, 1 ≤ y ≤ d − 1, gcd(i, h) = 1,
/// given integers c and d, 1 ≤ c ≤ 1.000.000, 1 ≤ d ≤ 1.000.000.
if ((1 == c) || (1 == d)) {
return 0; }
if (c > d) {
std::swap(c, d); }
std::vector<uint32_t> prime_factor(c, 0);
std::vector<uint32_t> signature(c, 1);
for (size_t p = 2; c > p; ++p) {
if (signature[p] == 1) {
for (size_t q = p; c > q; q += p) {
prime_factor[q] = static_cast<uint32_t>(p);
signature[q] *= static_cast<uint32_t>(p); }}}
std::vector<uint32_t> frequency(c, 0);
for (size_t q = 2; c > q; ++q) {
frequency[signature[q]] += 1; }
// 2·3·5·7·11·13·17 = 510510 < 10⁶ < 9699690 = 2·3·5·7·11·13·17·19, so
std::size_t max_number_of_distinct_prime_factors = 7;
std::vector<uint32_t> prime_factors(max_number_of_distinct_prime_factors);
size_t h = 0;
std::vector<uint32_t> prime_bit(1 << max_number_of_distinct_prime_factors);
std::vector<int32_t> product(1 << max_number_of_distinct_prime_factors);
product[0] = -1;
uint64_t total = (d - 1);
for (size_t q = 2; c > q; ++q) {
if (0 < frequency[signature[q]]) {
scan_distinct_prime_factors(signature[q], prime_factor.data(), prime_factors.data(), h);
uint32_t k = count__non_coprimes(prime_factors.data(), h, prime_bit.data(), product.data(), d - 1);
uint64_t c = ((d - 1) - k); // c ― the number of integers x, 1 ≤ x ≤ d − 1, coprime with signature[q].
total += frequency[signature[q]] * c;
frequency[signature[q]] = 0; }}
return total;
}
void scan_distinct_prime_factors ( size_t q
, uint32_t * prime_factor
, uint32_t * prime_factors
, size_t & h
) {
size_t t = 0;
uint32_t p = 0;
while (1 < q) {
p = prime_factor[q];
prime_factors[t++] = p;
q /= p; }
h = t;
}
uint32_t count__non_coprimes ( uint32_t const * prime_factors
, size_t const h
, uint32_t * prime
, int32_t * product
, uint32_t const b
) {
/// Returns the number of integers x, 1 ≤ x ≤ b, 2 ≤ gcd(x, q), q = ∏ j ← 0 … h − 1 ∷ prime_factors[j],
/// 1 ≤ q ≤ 10⁶, given that the array prime_factors[0 … h − 1] contains h distinct prime numbers,
/// using the intermediate data prime[0 … 1 << (h − 1)] and product[0 … 1 << (h − 1)].
/// Principle of inclusion-exclusion, at work! Go!
for (size_t i = 0; h > i; ++i) {
prime[1 << i] = prime_factors[i]; }
uint32_t total = 0;
for (size_t s = 1, t = (1 << h); t > s; ++s) {
// e ← LSB(s)
size_t e = (((s ^ (s - 1)) + 1) >> 1);
uint32_t p = prime[e];
int32_t x = -p * product[s ^ e];
uint32_t w = (0 > x) ? (-x) : (x);
product[s] = x;
total = (0 < x) ? (total + b/w) : (total - b/w); }
return static_cast<uint32_t>(total);
}