• + 0 comments

    My C++ sollution using fast matrix exponentiation at compile time.

    #include <array>
    #include <bitset>
    #include <cstdint>
    #include <iostream>
    
    using u32 = std::uint32_t;
    using u64 = std::uint64_t;
    
    struct u64_p
    {
        constexpr static u64 P{ 1000000007u };
    
        constexpr u64_p() = default;
        constexpr u64_p( u64 value ) : m_value { value % P }{}
        constexpr u64_p operator+( u64_p r ) const{ return { m_value + r.m_value }; }
        constexpr u64_p operator*( u64_p r ) const{ return { m_value * r.m_value }; }
    
        u64 m_value{};
    };
    
    constexpr u64_p operator""_p( unsigned long long number )
    {
        return u64_p{ static_cast<u64>( number ) };
    }
    
    struct Vec
    {
        u64_p m_a{};
        u64_p m_b{};
    };
    
    struct Matrix
    {
        constexpr Matrix operator*( Matrix r ) const
        { 
            return 
            { m_a * r.m_a + m_b * r.m_c
            , m_a * r.m_b + m_b * r.m_d
            , m_c * r.m_a + m_d * r.m_c
            , m_c * r.m_b + m_d * r.m_d };
        }
        constexpr Vec operator*( Vec r ) const
        { 
            return 
            { m_a * r.m_a + m_b * r.m_b
            , m_c * r.m_a + m_d * r.m_b };
        }
    
        u64_p m_a{};
        u64_p m_b{};
        u64_p m_c{};
        u64_p m_d{};
    };
    
    constexpr Matrix IDENTITY{ 1_p, 0_p, 0_p, 1_p };
    constexpr Matrix LAMBDA{ 1_p, 1_p, 1_p, 0_p };
    constexpr std::size_t U32_BITCOUNT{ 32u };
    
    constexpr auto LAMBDA_POWERS_2_POW_I{
        []() constexpr
        {
            std::array<Matrix, U32_BITCOUNT> matrices{};
            matrices[ 0u ] = LAMBDA;
            for ( std::size_t i{ 1u }; i < U32_BITCOUNT; ++i )
            {
                matrices[ i ] = matrices[ i - 1u ] * matrices[ i - 1u ];
            }
            return matrices;
        }()
    };
    
    Matrix pow_lambda( const u32 exponent )
    {
        const std::bitset<U32_BITCOUNT> bits{ exponent };
        Matrix result{ IDENTITY };
        for( std::size_t i{}; i < U32_BITCOUNT; i++ )
        {
            if( bits.test( i ) )
            {
                result = result * LAMBDA_POWERS_2_POW_I[ i ];
            }
        }
        return result;
    }
    
    u64 solve( const u64 a, const u64 b, const u32 n ) {
        return ( pow_lambda( n - 1 ) * Vec{ b, a } ).m_a.m_value;
    }
    
    int main()
    {
        std::size_t t{};
        std::cin >> t;
        while( t-- )
        {
            u64 a{}, b{};
            u32 n{};
            std::cin >> a >> b >> n;
            std::cout << solve( a, b, n ) << std::endl;
        }
    }