题目描述
小H是个善于思考的学生,现在她又在思考一个有关序列的问题。
她的面前浮现出一个长度为n的序列{ai},她想找出一段区间[L, R](1 <= L <= R <= n)。
这个特殊区间满足,存在一个k(L <= k <= R),并且对于任意的i(L <= i <= R),ai都能被ak整除。这样的一个特殊区间 [L, R]价值为R - L。
小H想知道序列中所有特殊区间的最大价值是多少,而有多少个这样的区间呢?这些区间又分别是哪些呢?你能帮助她吧。
输入
第一行,一个整数n.
第二行,n个整数,代表ai.
输出
第一行两个整数,num和val,表示价值最大的特殊区间的个数以及最大价值。
第二行num个整数,按升序输出每个价值最大的特殊区间的L.
样例输入
5
4 6 9 3 6
样例输出
1 3
2
提示
【样例输入2】
5
2 3 5 7 11
【样例输出2】
5 0
1 2 3 4 5
【数据范围】
30%: 1 <= n <= 30 , 1 <= ai <= 32.
60%: 1 <= n <= 3000 , 1 <= ai <= 1024.
80%: 1 <= n <= 300000 , 1 <= ai <= 1048576.
100%: 1 <= n <= 500000 , 1 <= ai < 2 ^ 31.
“ai都能被ak整除”,换句话说就是这段区间的最小值为这段区间的gcd。于是我们二分答案,用RMQ来寻找区间最小值和区间gcd,判断是否合法。详见代码。
var
n,i,l,r,mid,sum,k:longint;
fa,mini,g:array[0..500005,0..18] of longint;
a,ans:array[0..500005] of longint;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
function gcd(a,b:longint):longint;
begin
if b=0 then exit(a);
if a mod b=0 then exit(b) else exit(gcd(b,a mod b));
end;
function check(len:longint):longint;
var
i,l,r,k,num,gc,mimi:longint;
begin
sum:=0;
for i:=1 to n-len do
begin
l:=i;
r:=i+len;
k:=len+1;
for num:=18 downto 0 do
if k >> num and 1=1 then break;
k:=1<<num;
mimi:=min(mini[l,num],mini[r-k+1,num]);
gc:=gcd(g[l,num],g[r-k+1,num]);
if mimi=gc then
begin
sum:=sum+1;
ans[sum]:=l;
end;
end;
exit(sum);
end;
begin
readln(n);
for i:=1 to n do
begin
read(a[i]);
fa[i,0]:=i+1;
mini[i,0]:=a[i];
g[i,0]:=a[i];
end;
for k:=1 to 18 do
for i:=1 to n do
begin
fa[i,k]:=fa[fa[i,k-1],k-1];
mini[i,k]:=min(mini[i,k-1],mini[fa[i,k-1],k-1]);
g[i,k]:=gcd(g[i,k-1],g[fa[i,k-1],k-1]);
end;
l:=0;
r:=n-1;
while l<>r do
begin
mid:=(l+r+1) div 2;
if check(mid)<>0 then l:=mid
else r:=mid-1;
end;
check(l);
writeln(sum,' ',l);
for i:=1 to sum-1 do
write(ans[i],' ');
write(ans[sum]);
end.