这是一场比赛Q:
有N个数字a [0],a [1] ... a [N-1]。最初都是0.你必须执行两种类型的操作:
输入:第一行包含两个整数,N和Q.
如下所述,下一个Q行中的每一行都是“0 A B”或“1 A B”的形式。
输出:为“1 A B”形式的每个查询输出1行,其中包含相应查询的必需答案。
示例输入:
4 7 1 0 3 0 1 2 0 1 3 1
0 0 0 0 3 1 3 3 1 0 3
示例输出:
4 1 0 2
约束:
1 <= N <= 100000 1 <= Q <= 100000 0 <= A <= B <= N - 1
我不知道如何解决这个问题。你能帮忙吗?
时限为1秒。我试过蛮力,我也尝试在每个i的第i个元素之前保存3个除数。
这是我的C代码:
#include <stdio.h>
int nums[100*1000+20];
int d[100*1000+20];
int e[100*1000+20];
int dah[100*1000+20];
int main()
{
int n,q;
scanf("%d%d",&n,&q);
int h;
for(h=0;h<n;h++)
{d[h/100]++; e[h/1000]++; dah[h/10]++;}
int test;
for(test=0;test<q;test++)
{
int op,start,end;
scanf("%d%d%d",&op,&start,&end);
if(0==op)
{
int x;
for(x=start;x<=end;x++)
{
nums[x]++;
nums[x]%=3;
if(nums[x]==0)
{
d[x/100]++;
e[x/1000]++;
dah[x/10]++;
}
else if(nums[x]==1)
{
d[x/100]--;
e[x/1000]--;
dah[x/10]--;
}
}
}
else if(1==op)
{
int f;
int ans=0;
for(f=start;f<=end;)
{
if(f%1000==0&&f+1000<end)
{
ans+=e[f/1000];
f+=1000;
}
else if(f%100==0&&f+100<end)
{
ans+=d[f/100];
f+=100;
}
else if(f%10==0&&f+10<end)
{
ans+=dah[f/10];
f+=10;
}
else
{
ans+=(nums[f]==0);
f++;
}
}
printf("%d\n",ans);
}
}
return 0;
}
在这种方法中,我在k * 1000和(k + 1)* 1000之间保存3的倍数,对于k * 100和(k + 1)* 100以及10也保存相同的数量。这有助于我查询更快。但这让我的时间限制超过了。
答案 0 :(得分:5)
提示#1:
考虑一下如何使用MODULUS运算符来帮助您。最初,你有N个数字,假设N是5。
因此我们可以存储每个数字的余数(即存储0 MOD 3,1 MOD 3,2 MOD 3等):
a[0] = 0
a[1] = 1
a[2] = 2
a[3] = 0
a[4] = 1
a[5] = 2
每次增加A和B之间的数字范围时,实际上只需要在数组中存储0,1或2。例如,如果我们递增2,则新数字将为3.现在可以被3整除,因此我们在数组中存储0。所以在我们有0并且我们增加的情况下,我们存储1,如果我们有1存储2,如果我们有2存储0。
除了初始步骤之外,这种优化消除了进行任何除法的需要。分部是一项非常昂贵的操作,这就是我们希望尽可能消除它的原因。
因此,在递增0到5之后,数组将如下所示:
a[0] = 1
a[1] = 2
a[2] = 0
a[3] = 1
a[4] = 2
a[5] = 0
A和B之间可被3整除的数字量只是0的元素数(在这种情况下为2)。
现在你必须考虑如何有效地查询范围A到B,以找到可被3整除的数字量。
提示#2:
要找出区间[A,B]上可以被3整除的数量,您可以考虑使用的一种算法/数据结构是一个分段树。阅读它here。这给你带来的是现在你可以很快地计算任何这样的区间[A,B]可以被3整除的数字量,而不是在数组上循环并且必须对它们进行计数。
答案 1 :(得分:1)
提示#3:
dcp
的好建议。虽然它没有透露如何解决问题。 没有必要将所有数字MOD 3存储在数组中。如果每次在数组中更新数字,则复杂度为O(Q * N)
,这对于给定的N
来说显然太多了,Q
和1秒。在最坏的情况下。这是对Ali
建议的评论中dcp
的要点。
MOD%0
,MOD%1
,MOD%2
的整数可以存储在细分树的每个节点中。因此,可以在O(log N)
中完成更新,这会导致O(Q log N)
仅用于更新。对于每个查询,应用相同的复杂度O(log N)
。既然您知道每个残差的整数MOD%3,那么就没有必要去所有叶子(每个在分段树中留下的对应数组元素)来计算有多少数字可以被3整除。一旦你理解了分段树的工作原理,那么为什么有必要在分段树的每个节点中存储残差。该算法的整体复杂度为O(Q log N)
,非常适合1 sec. time limit
。
当向下移动分段树时,请务必为每个残留的整数累积,对于您在树下的路上访问的每个分段。
答案 2 :(得分:0)
你的数组的上限是多少?首先,想出来。然后,计划以这两种形式之一读取输入线。格式为0 A B的行很容易处理,你能编码至少这么多吗?如果是这样,发布它然后担心格式为1 A B的行。
答案 3 :(得分:0)
如果您的标题显示,您不确定如何判断一个数字是否可被3整除,那么我建议您查看modulus operation,我最熟悉的语言使用%
表示。