简体   繁体   English

如何找到3的倍数

[英]How to find number of Multiples of 3

This was a contest Q: 这是一场比赛Q:

There are N numbers a[0],a[1]..a[N - 1]. 有N个数字a [0],a [1] ... a [N-1]。 Initally all are 0. You have to perform two types of operations : 最初都是0.你必须执行两种类型的操作:

  1. Increase the numbers between indices A and B by 1. This is represented by the command "0 AB" 将索引A和B之间的数字增加1.这由命令“0 AB”表示
  2. Answer how many numbers between indices A and B are divisible by 3. This is represented by the command "1 AB". 回答索引A和B之间的数字可以被3整除。这由命令“1 AB”表示。

Input : The first line contains two integers, N and Q. 输入:第一行包含两个整数,N和Q.

Each of the next Q lines are either of the form "0 AB" or "1 AB" as mentioned above. 如上所述,下一个Q行中的每一行都是“0 AB”或“1 AB”形式。

Output : Output 1 line for each of the queries of the form "1 AB" containing the required answer for the corresponding query. 输出:为“1 AB”形式的每个查询输出1行,其中包含相应查询的必需答案。

Sample Input : 样本输入:

4 7 1 0 3 0 1 2 0 1 3 1
0 0 0 0 3 1 3 3 1 0 3

Sample Output : 样本输出:

4 1 0 2

Constraints : 制约因素:

1 <= N <= 100000 1 <= Q <= 100000 0 <= A <= B <= N - 1

I have no idea how to solve this. 我不知道如何解决这个问题。 can you help please? 你能帮帮忙吗?

The time limit is 1 second. 时间限制是1秒。 I tried brute force and i also tried saving number of divisors of 3 coming before ith element for each i. 我试过蛮力,我也尝试在每个i的第i个元素之前保存3个除数。

here's my C code: 这是我的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;
}

In this approach I save number of multiples of 3 between k*1000 and (k+1)*1000 and also the same thing for k*100 and (k+1)*100 and also for 10. this helps me query faster. 在这种方法中,我在k * 1000和(k + 1)* 1000之间保存3的倍数,对于k * 100和(k + 1)* 100以及10也保存相同的数量。这有助于我更快地查询。 but this yet gives me time limit exceed. 但这还给了我超时的时间限制。

Hint #1: 提示#1:

Think about how you might use the MODULUS operator to help you. 考虑一下如何使用MODULUS运算符来帮助您。 Initially, you have N numbers, let's say N is 5. 最初,你有N个数字,假设N是5。

So we can store the remainders for each number (ie store 0 MOD 3, 1 MOD 3, 2 MOD 3, and so on): 因此我们可以存储每个数字的余数(即存储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

Each time you increment a range of numbers between A and B, you really only need to store a 0, 1, or 2 in the array. 每次增加A和B之间的数字范围时,实际上只需要在数组中存储0,1或2。 For example, if we are incrementing 2, then the new number will be 3. That is now divisible by 3, so we store 0 in the array. 例如,如果我们递增2,则新数字将为3.现在可以被3整除,因此我们在数组中存储0。 So in cases where we have 0 and we increment, we store 1, if we have 1 we store 2, and if we have 2 we store 0. 所以在我们有0并且增加的情况下,我们存储1,如果我们有1我们存储2,如果我们有2我们存储0。

This optimization eliminates the need to do any division except for the initial step. 除了初始步骤之外,这种优化消除了进行任何除法的需要。 Division is a very expensive operation, which is why we want to eliminate it where we can. 分部是一项非常昂贵的操作,这就是我们希望尽可能消除它的原因。

So after incrementing 0 through 5, the array would look like this: 所以在递增0到5之后,数组看起来像这样:

a[0] = 1
a[1] = 2
a[2] = 0
a[3] = 1
a[4] = 2
a[5] = 0

The amount of numbers between A and B that are divisible by 3 is just the number of elements that have 0 (2 in this case). A和B之间可被3整除的数字量只是具有0的元素的数量(在这种情况下为2)。

Now you have to think about how to query a range A through B efficiently to find the amount of numbers divisible by 3. 现在你必须考虑如何有效地查询范围A到B,以找到可被3整除的数字量。

Hint #2: 提示#2:

To find out how many numbers over the interval [A,B] are divisible by 3, one algorithm/data structure you can consider using is a segment tree. 为了找出区间[A,B]上可以被3整除的数量,您可以考虑使用的一种算法/数据结构是一个分段树。 Read about it here . 在这里阅读它。 What this buys you is that now you can compute the amount of numbers divisible by 3 for any such interval [A,B] very quickly, instead of looping over the array and having to count them. 这给你买的是现在你可以很快地计算任何这样的区间[A,B]可以被3整除的数字量,而不是在数组上循环而不得不计算它们。

Hint #3: 提示#3:

Good suggestion by dcp . dcp好建议。 Though it doesn't reveal how to solve the problem. 虽然它没有透露如何解决问题。 It's not necessary to store all numbers MOD 3 in the array. 没有必要将所有数字MOD 3存储在阵列中。 If the numbers are updated every time in the array the complexity is O(Q * N) which is obviously too much for given N , Q and 1 sec. 如果每次在阵列中更新数字,则复杂度为O(Q * N) ,对于给定的NQ和1秒,这显然是太多了。 in the worst case. 在最坏的情况下。 That is the point of Ali in the comment to dcp suggestion. 这是Ali在对dcp建议的评论中的观点。

The number of integers with MOD%0 , MOD%1 , MOD%2 can be stored in each node of the segment tree. 具有MOD%0MOD%1MOD%2的整数的数量可以存储在段树的每个节点中。 Hence the updates can be done in O(log N) , which results in O(Q log N) for updates only. 因此,更新可以在O(log N) ,这导致O(Q log N)仅用于更新。 For each query the same complexity O(log N) applies. 对于每个查询,应用相同的复杂度O(log N) Since you know the number of integers MOD%3 for each residue, it's not necessary to go down to all leaves ( each leave in segment tree corresponds to array element ) to figure how many numbers are divisible by 3. Once you understand how segment tree works that should be obvious why it is necessary to store residues in each node of the segment tree. 既然你知道每个残差的整数MOD%3的数量,就没有必要去掉所有的叶子( 每个叶子对应于数组元素 )来计算有多少个数字可以被3整除。一旦你理解了如何分割树为什么有必要在段树的每个节点中存储残差的工作应该是显而易见的。 Overall complexity of the algorithm is O(Q log N) which will fit nicely in 1 sec. time limit 该算法的总体复杂性是O(Q log N) ,它将在1 sec. time limit很好地拟合1 sec. time limit 1 sec. time limit . 1 sec. time limit

When going down the segment tree be sure to accumulate number of integers per residue, for each segment that you visit on the way down the tree. 当向下移动分段树时,请确保为每个残留的整数累积,对于您在树下的路上访问的每个分段。

what's the upper bound for your array? 你的数组的上限是多少? first, figure that out. 首先,想出来。 Then, plan on reading lines of input in one of those two forms. 然后,计划以这两种形式之一读取输入线。 The lines in format 0 AB are easy to handle, can you code at least that much? 0 AB格式的行很容易处理,你能编码至少这么多吗? If so, post it and then worry about the lines in format 1 A B. 如果是这样,发布它然后担心格式为1 A B的行。

如果,正如你的标题所示,你不确定如何判断一个数字是否可被3整除,那么我建议你看一下模数运算 ,我最熟悉的语言用%表示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM