以低复杂度计算K个连续数字模组1000000007的LCM的程序
Program to calculate LCM of K consecutive numbers mod 1000000007 with low complexity
我必须编写一个程序,以便为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]) = l1
和lcm([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);
这不是优化的解决方案,但应该有效。作为数据结构使用的段树。如果您真的不需要更新操作,稀疏表也可以在此处使用。
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 检查输入是否不是整数或数字
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- 如何用数字处理log(0)
- 最高有效数字侧的第N位
- 如何获取一个数字的前3位
- 查找最接近的大于当前数字的数字的索引
- 找到两对数字,使它们的乘积的绝对差最小化
- 我想做一个彼此不同但重复出现的数字
- 将数字转换为字母(例如:123 转换为一二三)
- C++如何计算用户输入的数字中的偶数位数
- 如何在C++中确定文本文件中的元素是字符还是数字
- 打印数字图案
- C++问题:用户认为数字1-100,程序提出问题不超过6次即可得到答案。无法正确
- 如何检查一个c++字符串中有多少相同的字符/数字
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 将数字打印成文字
- 当使用比格式支持的精度更高的精度来显示数字时,会写出什么数据
- 在将数字随机生成为数组期间从内存输出随机数的数组