我有一个N
最多为10 ^ 5的数组。
我需要使用给定的Q
和L
解决R
范围查询。
Q
<= 10 ^ 5
对于每个查询,我需要在L到R范围内找到不同的元素 然后找到他们的阶乘。
例如,如果数组为{5, 4, 2, 4, 5, 5, 7}
。
如果L = 2
和R = 4
。
那么我们有了{ 4 : 2 times, 2: 1 time }
,答案是(2!)*(1!) = 2
。
如果L = 1
和R = 5
那么我们有了{5 : 2 times, 4: 2 times, 2 : 1 time}
,答案是(2!)*(2!).(1!) = 4
。
O((N)*(Q))
显然可以解决此问题。
我该如何优化它。
注意:所有阶乘均以1000000007为模计算
答案 0 :(得分:3)
好的,因为(根据您的评论),数组中只能有10 5 个元素,这也是数组中每个可能值的最大 count 个
因此,您可以做的一件事就是将所有这些阶乘因子预先计算到一个数组中,然后将其用于计算。
可能最好的方法是编写一个元程序,将值构造成C ++结构,然后将其包含在自己的代码中(a)。结构如下所示:
unsigned int facMod10p7[] = {
0,
1,
2,
:
/* whatever (10^5)! % 1000000007 is */
};
一旦有了,每个阶乘的查找就是O(1)。要进行查询,您只需遍历数组(从L
到R
),计算唯一值的数量即可。
最好用map<unsigned int, unsigned int>
来完成,第一个字段是值(假设此处为未签名的值,但您可以很容易地使该符号签名),第二个字段为出现的次数。
对于L2/R4
的{{1}}情况,您最终会得到一张地图,因此:
{4, 2, 4}
然后,只需简单地遍历一下,即可为每个计数查找阶乘并取所有乘积。
由于它是O(n)循环中的O(1)查找/乘法,因此复杂度将为O(n)。
(a)例如,用于输出前10,000个阶乘的Python程序在我的盒子上花费大约30秒的时间来生成整个表(在我的WSL环境中,不一定以其盲目性而闻名。 / O速度,至少要等到即将发布的下一个版本为止):
{ [2] = 1, [4] = 2 }
如果要进行自己的测试,则代码为:
real 0m29.137s
user 0m28.438s
sys 0m0.547s
答案 1 :(得分:3)
让我们考虑一下您的示例:
n = 7
A[n] = {5, 4, 2, 4, 5, 5, 7}
L = 2
R = 4
p = 1000000007
计算H[]
的直方图A[]
,O(n)
大小为n
的数组中位于L,R
之间的所有值,其中m
是您的任何值的最大计数。
H[2] = 1
H[3] = 0
H[4] = 2
在代码中类似:
int H[R-L+1],i;
for (i=L,i<=R;i++) H[i-L]=0;
for (i=0,i<n;i++)
if ((A[i]>=L)&&(A[i]<=R)
H[i-L]++;
我将H
的索引移了L,所以我们不会浪费空间,所以:
H[0] = 1
H[1] = 0
H[2] = 2
找到m = max(H[])
的{{1}}
简单地:
O(R-L+1)
如此:
int m;
for (m=H[0],i=L+1;i<=R;i++)
if (m<H[i-L])
m=H[i-L];
预先计算所有m = 2
(即m
O(m)
如此:
int F[m+1],j;
j=1; F[0]=j;
for (i=1;i<=m;i++)
{
j=modmul(j,i,p); // j = j*i mod p
F[i]=j;
}
计算阶乘的最终PI为O(R-L + 1)
很简单:
F[] = { 0!,1!,2! }
F[] = { 0 ,1 ,2 }
如此:
for (j=1,i=L;i<=R;i++)
j=modmul(j,F[H[i-L]],p);
// here j is your result
您可以看到整个过程是j = F[H[0]]*F[H[1]]*F[H[2]]
j = F[1]*F[0]*F[2]
j = 1!*0!*2!
j = 2
,这比您的O(n+m+R-L)
如果您多次执行此操作,则应考虑将O(N*Q)
预计算为最大F[]
值...
如果我选择n
,则内容如下:
L=1,R=5
您的直方图中有错误,因为数组中有5个错误是3倍而不是2个!但是,如果将范围应用于数组的索引而不是其值,则不是错误,而我的方法需要对索引稍作更改...周期的所有// 1 2 3 4 5
H[] = { 0,1,0,2,3 }
m = 3
// 0 1 2 3
F[] = { 1,1,2,6 }
PI(F[H]) = F[0]*F[1]*F[0]*F[2]*F[3]
= 1 * 1 * 1 * 2! * 3!
= 2*6
= 12
将从i
到改为L
。