繁体   English   中英

如何找到3的倍数

[英]How to find number of Multiples of 3

这是一场比赛Q:

有N个数字a [0],a [1] ... a [N-1]。 最初都是0.你必须执行两种类型的操作:

  1. 将索引A和B之间的数字增加1.这由命令“0 AB”表示
  2. 回答索引A和B之间的数字可以被3整除。这由命令“1 AB”表示。

输入:第一行包含两个整数,N和Q.

如上所述,下一个Q行中的每一行都是“0 AB”或“1 AB”形式。

输出:为“1 AB”形式的每个查询输出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也保存相同的数量。这有助于我更快地查询。 但这还给了我超时的时间限制。

提示#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整除的数量,您可以考虑使用的一种算法/数据结构是一个分段树。 在这里阅读它。 这给你买的是现在你可以很快地计算任何这样的区间[A,B]可以被3整除的数字量,而不是在数组上循环而不得不计算它们。

提示#3:

dcp好建议。 虽然它没有透露如何解决问题。 没有必要将所有数字MOD 3存储在阵列中。 如果每次在阵列中更新数字,则复杂度为O(Q * N) ,对于给定的NQ和1秒,这显然是太多了。 在最坏的情况下。 这是Ali在对dcp建议的评论中的观点。

具有MOD%0MOD%1MOD%2的整数的数量可以存储在段树的每个节点中。 因此,更新可以在O(log N) ,这导致O(Q log N)仅用于更新。 对于每个查询,应用相同的复杂度O(log N) 既然你知道每个残差的整数MOD%3的数量,就没有必要去掉所有的叶子( 每个叶子对应于数组元素 )来计算有多少个数字可以被3整除。一旦你理解了如何分割树为什么有必要在段树的每个节点中存储残差的工作应该是显而易见的。 该算法的总体复杂性是O(Q log N) ,它将在1 sec. time limit很好地拟合1 sec. time limit 1 sec. time limit

当向下移动分段树时,请确保为每个残留的整数累积,对于您在树下的路上访问的每个分段。

你的数组的上限是多少? 首先,想出来。 然后,计划以这两种形式之一读取输入线。 0 AB格式的行很容易处理,你能编码至少这么多吗? 如果是这样,发布它然后担心格式为1 A B的行。

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

暂无
暂无

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

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