jzoj100045. 好数

版权声明:本人初三蒟蒻一只,欢迎各位大佬来点评。 https://blog.csdn.net/HiChocolate/article/details/85015024

Description

我们定义一个非负整数是“好数”,当且仅当它符合以下条件之一:
1.这个数是0或1
2.所有小于这个数且与它互质的正整数可以排成一个等差数列例如,8就是一个好数,因为1,3,5,7排成了等差数列。
给出N个非负整数,然后进行如下三个操作:
1.询问区间[L,R]有多少个好数
2.将区间[L,R]内所有数对S取余(S≤1000000)
3.将第C个数更改为X

Input

第一行包含两个正整数N和M,M表示操作数目
第二行包含N个非负整数。
接下来的M行每行表示1个操作:“1 L R”表示第1个操作,“2 L R S”表示第2个操作,“3 C X”表示第3个操作。

Output

对每个操作1,输出一个非负整数,表示区间内好数的个数。

Sample Input

Sample1:
3 6
4 6 9
1 1 3
1 3 3
2 1 1 10
1 1 3
3 2 4
1 1 3
Sample2:
8 5
12 24 17 31 16 21 18 30
1 2 5
2 4 7 7
3 2 13
1 1 8
1 3 6

Sample Output

Sample1:
2
0
2
2
Sample2:
3
6
4

Data Constraint

0 < = n , m < = 1 0 5 , n < = 1 0 6 0<=n,m<=10^5,n个数大小<=10^6

题解

这题很巧妙。
首先我们要确定好数是那几个。
那么打表找规律
发现好数必须是质数、2的次幂或者6。
证明:
如果一个数为2的次幂,那么显然这个成立。
如果一个数为质数,这也是可以肯定正确的。
如果一个数不为质数且不是2的次幂。
那么就可以设这个数为 x 2 k x*2^k
当k不为0时。
可以发现,x为奇数。
那么,就可以知道 x 2 x-2 x + 2 x+2 必定与 x 2 k x*2^k 互质。
而且,根据常识, x 2 k 1 x*2^k-1 1 1 也是与 x 2 k x*2^k 互质的。
由于x-2和x+2靠的最近,而且中间的任何数都是与 x 2 k x*2^k 不互质的。
那么就可以确定了,从1开始每4个为一个互质的数。
那么,若有一个数与任意的 1 + 4 y 1+4*y 互质但与其他任何数都不互质,这个数就是好数。
列举一下可以发现,这个数如果大于等于了9,这个数就要即与9互质又与3不互质,不成立。
然而小于9时,只有一个6满足。

当k为0时。
显然上述条件不成立。
但是,显然的, x 1 x-1 x 2 x-2 x x 三个互质。
那么意味着,每个互质的数要连续。
然而比这个x小的数中,必然有个与它不互质。
那么这种情况就没有好数。

至此,证明完成。

接下来,我们知道了什么数字为好数,什么数字不为好数。
我们就可以快速判断了。

假设我们可以建一颗线段树,里面储存每个位置好数个数的情况。
如果一个位置为好数,线段树相应位置为1,反之为0。
这样可以快速解决1、3操作。
对于2操作,我们要对树取模操作。
这个显然有点棘手。
但是我们发现,一个数不改变的情况下,对任意一个数取模,要么不变,要么最大变成原来的一半。
那么就可以发现,一个数字最多被模log下。
至此,想到了什么?暴力!
记得之前有一个小技巧,就是线段树中维护最大的数字,如果某个区间最大数字超过模数,证明这个区间需要取模。
那么递归下去暴力修改即可。
理论最坏时间复杂度 O ( m l o g 2 1 0 6 ) O(m*log^210^6)
实际远小于这个复杂度。

代码

uses math;
var
        i,j,k,l,n,m,tot,ans:longint;
        gos,bz:array[0..2000000] of boolean;
        zs:array[2..2000000] of boolean;
        tree:array[1..4000000] of longint;
        zd:array[1..4000000] of longint;
        a,b:array[1..1000000] of longint;
        kind,x,y,z:array[1..1000000] of longint;
        qj:boolean;
procedure maketree(x,l,r:longint);
begin
        if l=r then
        begin
                tree[x]:=b[l];
                zd[x]:=a[l];
        end
        else
        begin
                maketree(x+x,l,(l+r)shr 1);
                maketree(x+x+1,(l+r)shr 1+1,r);
                tree[x]:=tree[x*2]+tree[x*2+1];
                zd[x]:=max(zd[x*2],zd[x*2+1]);
         end;
end;
procedure insert(x,l,r,st,value:longint);
var
        m,k:longint;
begin
        if (l=r) then
        begin
                if gos[value] then k:=1
                else k:=0;
                tree[x]:=k;
                zd[x]:=value;
        end
        else
        begin
                m:=(l+r)shr 1;
                if st<=m then insert(2*x,l,m,st,value)
                else insert(2*x+1,m+1,r,st,value);
                tree[x]:=tree[x*2]+tree[x*2+1];
                zd[x]:=max(zd[x*2],zd[x*2+1]);
        end;
end;
procedure gg(x,l,r,mo:longint);
var
        m:longint;
begin
        if (l=r) then
        begin
                zd[x]:=zd[x] mod mo;
                if gos[zd[x]] then
                tree[x]:=1
                else
                tree[x]:=0;
        end
        else
        begin
                m:=(l+r)shr 1;
                if (zd[x*2]>=mo) then gg(2*x,l,m,mo);
                if (zd[x*2+1]>=mo) then gg(2*x+1,m+1,r,mo);
                tree[x]:=tree[x*2]+tree[x*2+1];
                zd[x]:=max(zd[x*2],zd[x*2+1]);
        end;

end;
procedure change(x,l,r,st,en,mo:longint);
var
        m:longint;
begin
        if (l=st) and (r=en) then
        begin
                if zd[x]>=mo then
                begin
                        gg(x,l,r,mo);
                end;
        end
        else
        begin
                m:=(l+r)shr 1;
                if en<=m then change(2*x,l,m,st,en,mo)
                else if st>m then change(2*x+1,m+1,r,st,en,mo)
                else
                begin
                        change(2*x,l,m,st,m,mo);
                        change(2*x+1,m+1,r,m+1,en,mo);
                end;
                tree[x]:=tree[x*2]+tree[x*2+1];
                zd[x]:=max(zd[x*2],zd[x*2+1]);
        end;
end;
procedure look_for(x,l,r,st,en:longint);
var
        m:longint;
begin
        if (l=st)and(r=en) then
        begin
                inc(ans,tree[x]);
        end
        else
        begin
                m:=(l+r)shr 1;
                if en<=m then look_for(2*x,l,m,st,en)
                else if st>m then look_for(2*x+1,m+1,r,st,en)
                else
                begin
                        look_for(2*x,l,m,st,m);
                        look_for(2*x+1,m+1,r,m+1,en);
                end;
        end;
end;
begin
        fillchar(bz,sizeof(bz),true);
        for i:=2 to 1000000 do
        begin
                if bz[i] then
                for j:=2 to 1000000 div i do bz[i*j]:=false;
        end;
        l:=1;
        for i:=1 to 30 do
        begin
                l:=l*2;
                if l<1000000 then bz[l]:=true else break;
        end;
        bz[6]:=true;
        gos:=bz;

        readln(n,m);
        for i:=1 to n do
        begin
                read(a[i]);
                if gos[a[i]] then
                begin
                        b[i]:=1;
                end;
        end;
        maketree(1,1,n);
        for i:=1 to m do
        begin
                read(kind[i]);
                if kind[i]=2 then
                begin
                        qj:=true;
                        readln(x[i],y[i],z[i]);
                end;
                if kind[i]=1 then
                begin
                        readln(x[i],y[i]);
                end;
                if kind[i]=3 then
                begin
                        readln(x[i],z[i]);
                end;
        end;
        for i:=1 to m do
        begin
                if kind[i]=1 then
                begin
                        ans:=0;
                        look_for(1,1,n,x[i],y[i]);
                        writeln(ans);
                end
                else
                if kind[i]=2 then
                begin
                        change(1,1,n,x[i],y[i],z[i]);
                end
                else
                if kind[i]=3 then
                begin
                        insert(1,1,n,x[i],z[i]);
                end;
        end;
end.

猜你喜欢

转载自blog.csdn.net/HiChocolate/article/details/85015024
今日推荐