繁体   English   中英

我遇到了 10^9+7 问题,但我无法理解 mod 的分布属性与我的问题之间的关系

[英]I encountered the 10^9+7 problem but I can't understand the relation between the distributive properties of mod and my problem

给定 3 个数字 ab c 得到 a^b、b^a、c^x,其中 x 是 b 和 cout 之间的绝对差异,但按升序 mod 10^9+7。 好吧,我在 web 上搜索了如何使用分配属性,但因为我是初学者所以不明白,

我使用非常简单的 for 循环,所以理解这个问题对我来说有点困难,所以我如何在循环中将这些 mod 规则与权力联系起来? 如果有人能帮助我,我会很高兴。 注意时间限制是 1 秒,这使得它更难

我尝试在循环中每次都修改结果,然后将其乘以原始数字。 例如,如果 2^3 那么第一个循环给定变量 cin>>a,a 将是 2,num =a 将像这样 a = (a % 10^9 + 7) * num 这适用于非常小的输入但大的输入它超过了时间

#include <iostream>
#include <cmath>

using namespace std;
int main ()
{
    long long a,b,c,one,two,thr;
    long long x;
    long long mod = 1e9+7;
    cin>>a>>b>>c;
    one = a;
    two = b;
    thr = c;
    if (a>=b)
    x = a - b;
    else
    x = b - a;

    for(int i = 0; i < b-1;i++)
    {
        a = ((a % mod) * (one%mod))%mod;
    }
    for(int j = 0; j < a-1;j++)
    {
        b = ((b % mod) * (two%mod))%mod;
    }
    for(int k = 0; k < x-1;k++)
    {
        c = ((c % mod) * (thr%mod))%mod;
    }
}

我使用非常简单的 for 循环 [...] 这适用于非常小的输入,但大的输入会超过时间。

有一种称为“平方求幂”的算法,它具有对数时间复杂度,而不是线性时间复杂度。

它可以在增加基数的同时分解幂指数。

考虑,例如 x 355 而不是乘以 x 354次,我们可以观察到

x 355 = x·x 354 = x·(x 2 ) 177 = x·x 2 ·(x 2 ) 176 = x·x 2 ·(x 4 ) 88 = x·x 2 ·(x 8 ) 44 = x ·x 2 ·(x 16 ) 22 = x·x 2 ·(x 32 ) 11 = x·x 2 ·x 32 ·(x 32 ) 10 = x·x 2 ·x 32 ·(x 64 ) 5 = x ·x 2 ·x 32 ·x 64 ·(x 64 ) 4 = x·x 2 ·x 32 ·x 64 ·(x 128 ) 2 = x 1 ·x 2 ·x 32 ·x 64 ·x 256

这“只”走了12步。

要实现它,我们只需要能够安全地执行模乘法,而不会溢出。 给定模数的值,像std::int64_t这样的类型就足够宽了。

#include <iostream>
#include <cstdint>
#include <limits>
#include <cassert>

namespace modular
{
  auto exponentiation(std::int64_t base, std::int64_t exponent) -> std::int64_t;
}

int main()
{
  std::int64_t a, b, c; 
  std::cin >> a >> b >> c;  

  auto const x{ b < a ? a - b : b - a };

  std::cout << modular::exponentiation(a, b) << '\n'
            << modular::exponentiation(b, a) << '\n'
            << modular::exponentiation(c, x) << '\n';

  return 0;
}

namespace modular
{
  constexpr std::int64_t M{ 1'000'000'007 };

  // We need the mathematical modulo
  auto from(std::int64_t x)
  {
    static_assert(M > 0);
    x %= M;
    return x < 0 ? x + M : x;
  }

  // It assumes that both a and b are already mod M
  auto multiplication_(std::int64_t a, std::int64_t b)
  {
    assert( 0 <= a  and a < M  and  0 <= b  and  b < M );
    assert( b == 0  or  a <= std::numeric_limits<int64_t>::max() / b );

    return (a * b) % M;
  }

  // Implements exponentiation by squaring
  auto exponentiation(std::int64_t base, std::int64_t exponent) -> std::int64_t
  {
    assert( exponent >= 0 );
    
    auto b{ from(base) };
    std::int64_t x{ 1 };
    while ( exponent > 1 )
    {
      if ( exponent % 2 != 0 )
      {
        x = multiplication_(x, b);
        --exponent;
      }
      b = multiplication_(b, b);
      exponent /= 2;
    }
    return multiplication_(b, x);
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM