Cod sursa(job #2703698)

Utilizator mgntMarius B mgnt 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);                                                                               
                                                                                                                       
}