以低复杂度计算K个连续数字模组1000000007的LCM的程序

Program to calculate LCM of K consecutive numbers mod 1000000007 with low complexity

本文关键字:1000000007 数字 LCM 程序 连续 复杂度 计算      更新时间:2023-10-16

我必须编写一个程序,以便为L,R类型的多个查询我必须将数字的 LCM 从 L 输出到 R。其中 R 可以最大转到 M

我已经设法编写了一个复杂度 N(Q( 的程序。M ,我需要在 N(Q( 中执行此操作。Log(M( 或 N(Q(.sqrt(M( .

这里的 N(Q( 表示没有查询。 sqrt 表示平方根。

编辑:我使用 Segmentree 编写了它,但是得到一个错误的答案,在这里 powf 在登录时间内找到 a^b % P:我的查询代码:

 long long findfunc(long long ql,long long qr,long long ind)
  {
 if(a >qr || b<ql)
   return 1;
 if(a>=ql && b<=qr)
  { //cout<<"LCM "<<ql<<" to "<<qr<<" "<<val[ind]<<endl; 
   return  val[ind]%mod;
  }
 else
  {
 ll vl= findfunc(ql,qr,2*ind+1);
 ll vr= findfunc(ql,qr,2*ind+2);
 return  ( ((vl*vr)%mod) * powf(gcd(vl,vr),mod-2)  )%mod;
 }  
}

您可以使用段树。这个想法是在每个节点中存储l, l+1, ..., r的最小公倍数,表示区间[l, r]

  • 如何构建 - 您自下而上地开始,当您必须合并到节点时[a, b][b+1, c]执行以下操作。让lcm([a, b]) = l1lcm([b+1, c]) = l2然后lcm([a, c]) = lcm(lcm([a, b]), lcm([b+1, c])) = lcm(l1, l2) = l1*l2 / gcd(l1,l2).由于gcd(l1,l2)大致是恒定的,因此合并操作是恒定的。

  • 如何查询 - 如果您有间隔[a, b]则可以在树中找到节点,以便它们表示某些c[a, c][c+1, b]的范围。然后lcm([a, b])的计算与合并步骤中的计算相同。

您正在寻找名为 Segment Trees 的数据结构。我不会提供代码,因为这不是我们在SO上所做的。

此链接:

https://www.topcoder.com/community/data-science/data-science-tutorials/range-minimum-query-and-lowest-common-ancestor/

会对你有所帮助。

我不是C++专家,你可以看看我的C#实现,我相信这转换到C++并不难。

private const int Mid = 128 * 1024;
private static long mod = 1000000007;
private static long[] t = new long[Mid + Mid];
public static void Initialize(long[] a)
{
    for (int i = 0; i < a.Length; i++) t[Mid + i] = a[i];
    for (int i = a.Length; i < Mid; i++) t[Mid + i] = 1;
    for (int i = Mid - 1; i > 0; i--) t[i] = LCM(t[i + i], t[i + i + 1]);
}
public static long GetLcm(int l, int r)
{
    l += Mid;
    r += Mid;
    long ans = 1;
    while (l <= r)
    {
        ans = LCM(ans, t[l]);
        ans = LCM(ans, t[r]);
        l = (l + 1) / 2;
        r = (r - 1) / 2;
    }
    return ans;
}
public static void Update(int i, long v)
{
    i += Mid;
    t[i] = v;
    while (i > 0)
    {
        i = i / 2;
        t[i] = LCM(t[i + i], t[i + i + 1]);
    }
}
private static long GCD(long a, long b)
{
    if (a % b == 0) return b;
    return GCD(b, a % b);
}
private static long LCM(long a, long b)
{
    if (a == 0 || b == 0) return 0;
    return ((a * b) / GCD(a, b)) % mod;
}

您可以通过以下代码使用它:

    long[] m = new long[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    Initialize(m);
    var ans1 = GetLcm(0, 9);
    Update(8, 6);
    var ans2 = GetLcm(0, 9);

这不是优化的解决方案,但应该有效。作为数据结构使用的段树。如果您真的不需要更新操作,稀疏表也可以在此处使用。