【问题标题】:Program to calculate LCM of K consecutive numbers mod 1000000007 with low complexity以低复杂度计算 K 个连续数 mod 1000000007 的 LCM 的程序
【发布时间】:2015-10-09 06:54:06
【问题描述】:

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

我设法编写了一个复杂度为 N(Q).M 的程序, 我需要在 N(Q).Log(M) 或 N(Q).sqrt(M) 中进行。

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

编辑:我使用 Segmentree 编写了它,但是得到了错误的答案,这里 powf 在 logn time 中找到 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;
 }  
}

【问题讨论】:

  • M 的限制是多少?
  • M 可以到 10^5,N(Q) 可以到 10^6
  • 尝试学习Segment Trees
  • 我已经知道了,但是对查询操作感到困惑
  • 您是否只有获取 LCM 或更新项目查询?

标签: c++ algorithm primes prime-factoring


【解决方案1】:

您可以使用segment tree。这个想法是在代表区间[l, r]的每个节点中存储l, l+1, ..., 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],您会在树中找到节点,它们代表 [a, c][c+1, b] 范围内的一些 c .那么lcm([a, b])的计算与合并步骤中的一样。

【讨论】:

  • if(a >qr || b=ql && b
  • 在使用 GCD(l1,l2) 的 mod 乘法逆时得到错误的答案
  • @smartsn123 我猜你的代码有错误?为什么不用简单的案例来测试呢?
  • 如果没有 mod 乘法逆,我可以通过除以 gcd(l1,l2) 来处理小型测试用例,但使用 modmulInverse 即使对于 gmall 测试用例,我也会出错。所以我猜 Segmentree 代码很好,但是使用 modMulInv 会搞砸。
  • 请查看我在 EDIT 中的上述代码并建议可能出现错误
【解决方案2】:

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

此链接:

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

会对你有所帮助。

【讨论】:

  • 我知道,但是对合并两个范围感到困惑
  • @svs 为您的困惑写了一个很好的答案。
【解决方案3】:

我不是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);

这不是优化的解决方案,但应该可以。 作为数据结构使用段树。 如果真的不需要 Update 操作 SparseTable 也可以在这里使用。

【讨论】:

    猜你喜欢
    • 2012-03-22
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 2017-04-12
    • 2017-08-31
    • 2015-12-01
    相关资源
    最近更新 更多