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
题解
这题很巧妙。
首先我们要确定好数是那几个。
那么打表找规律
发现好数必须是质数、2的次幂或者6。
证明:
如果一个数为2的次幂,那么显然这个成立。
如果一个数为质数,这也是可以肯定正确的。
如果一个数不为质数且不是2的次幂。
那么就可以设这个数为
当k不为0时。
可以发现,x为奇数。
那么,就可以知道和必定与互质。
而且,根据常识,和也是与互质的。
由于x-2和x+2靠的最近,而且中间的任何数都是与不互质的。
那么就可以确定了,从1开始每4个为一个互质的数。
那么,若有一个数与任意的互质但与其他任何数都不互质,这个数就是好数。
列举一下可以发现,这个数如果大于等于了9,这个数就要即与9互质又与3不互质,不成立。
然而小于9时,只有一个6满足。
当k为0时。
显然上述条件不成立。
但是,显然的,和和三个互质。
那么意味着,每个互质的数要连续。
然而比这个x小的数中,必然有个与它不互质。
那么这种情况就没有好数。
至此,证明完成。
接下来,我们知道了什么数字为好数,什么数字不为好数。
我们就可以快速判断了。
假设我们可以建一颗线段树,里面储存每个位置好数个数的情况。
如果一个位置为好数,线段树相应位置为1,反之为0。
这样可以快速解决1、3操作。
对于2操作,我们要对树取模操作。
这个显然有点棘手。
但是我们发现,一个数不改变的情况下,对任意一个数取模,要么不变,要么最大变成原来的一半。
那么就可以发现,一个数字最多被模log下。
至此,想到了什么?暴力!
记得之前有一个小技巧,就是线段树中维护最大的数字,如果某个区间最大数字超过模数,证明这个区间需要取模。
那么递归下去暴力修改即可。
理论最坏时间复杂度
实际远小于这个复杂度。
代码
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.