Simon has an array a1, a2, ..., an, consisting of n positive integers. Today Simon asked you to find a pair of integers l, r (1 ≤ l ≤ r ≤ n), such that the following conditions hold:
- there is integer j (l ≤ j ≤ r), such that all integers al, al + 1, ..., ar are divisible by aj;
- value r - l takes the maximum value among all pairs for which condition 1 is true;
Help Simon, find the required pair of numbers (l, r). If there are multiple required pairs find all of them.
The first line contains integer n (1 ≤ n ≤ 3·105).
The second line contains n space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 106).
Print two integers in the first line — the number of required pairs and the maximum value of r - l. On the following line print all l values from optimal pairs in increasing order.
5 4 6 9 3 6
1 3 2
5 1 3 5 7 9
1 4 1
5 2 3 5 7 11
5 0 1 2 3 4 5
In the first sample the pair of numbers is right, as numbers 6, 9, 3 are divisible by 3.
In the second sample all numbers are divisible by number 1.
In the third sample all numbers are prime, so conditions 1 and 2 are true only for pairs of numbers (1, 1), (2, 2), (3, 3), (4, 4), (5, 5).
题目大意:
给你N个数,让你找到所有的区间【L,R】,使得R-L是最大的值而且区间内有一个数可以被其他所有数整除.
思路:
1、找到一个区间【L,R】使得其中存在一个数可以被其他所有数都整除,那么其实就是要满足条件:Min(a[i])【L<=i<=R】==Gcd【L,R】;
2、我们还知道,假设我们有一个起点i,那么我们不断的增大区间右端点的位子的话,会使得Gcd逐渐变小,min值也逐渐变小。
这里肯定是存在一个单调性的,但是我们O(n)枚举起点然后二分终点的话,我们要确定下来一个最小值的问题,而且两个值都在变小,我们相对check起来有点难。
那么我们不妨换个角度去做。
我们O(n)枚举一个位子i,使得这个位子i作为区间中的最小值,那么我们向左二分最远点,使得【L,i】的最小值等于a【i】,然后向右二分一个最远点,使得【i,R】的最小值也等于a【i】,那么我们现在就通过这个方式取得了一个区间【L,R】是以a【i】作为最小值的一个区间。
我们知道,如果以这个位子i作为中心点向左扩大区间的话,其Gcd的值要么会下降,要么会保持不变,其也包含一个单调性
所以我们接下来再以i作为中心点,
向左二分找到最远点,使得Gcd【ansL,i】是等于a【i】的,
再向右二分找到最远点,使得Gcd【i,ansR】也是等于a【i】的。
那么对于a【i】作为中心点的最优解就是【ansL,ansR】了,过程维护最优解即可。
3、一开始用线段树跑的区间最小值和Gcd值,TLE了,O(n*logn*longn),n相对有些大 。
这个题是静态不会改变A【i】数组的一个题,所以我们不妨维护一个ST表,就能做到O(1)查询,所以用ST表求Gcd和最小值的时间复杂度为O(nlogn);
Ac代码:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<math.h>
#include<map>
using namespace std;
#define lson l,m,rt*2
#define rson m+1,r,rt*2+1
int flag,cnt,maxn;
vector<int >ans;
map<int,int>s;
int a[1221212];
int minn[400005][20];
int Gcd[400005][20];
int n,q;
int gcd(int x,int y)
{
return y==0?x:gcd(y,x%y);
}
void ST()
{
int len=floor(log10(double(n))/log10(double(2)));
for(int j=1;j<=len;j++)
{
for(int i=1;i<=n+1-(1<<j);i++)
{
minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);
Gcd[i][j]=gcd(Gcd[i][j-1],Gcd[i+(1<<(j-1))][j-1]);
}
}
}
int getminn(int a,int b)
{
int len= floor(log10(double(b-a+1))/log10(double(2)));
return min(minn[a][len], minn[b-(1<<len)+1][len]);
}
int getGcd(int a,int b)
{
int len= floor(log10(double(b-a+1))/log10(double(2)));
return gcd(Gcd[a][len],Gcd[b-(1<<len)+1][len]);
}
void Slove(int L,int R,int i)
{
int ansL=-1;
int l=L;
int r=i;
while(r-l>=0)
{
int mid=(l+r)/2;
if(getGcd(mid,i)==a[i])
{
ansL=mid;
r=mid-1;
}
else l=mid+1;
}
if(ansL==-1)return ;
int ansR=-1;
l=i;
r=R;
while(r-l>=0)
{
int mid=(l+r)/2;
if(getGcd(i,mid)==a[i])
{
l=mid+1;
ansR=mid;
}
else r=mid-1;
}
if(ansR==-1||ansL==-1)return ;
if(ansR-ansL>maxn)
{
s.clear();
ans.clear();
maxn=ansR-ansL;
}
if(ansR-ansL==maxn)
{
if(s[ansL]==0)
ans.push_back(ansL),s[ansL]=1;
}
}
int main()
{
while(~scanf("%d",&n))
{
maxn=-1;
flag=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
minn[i][0]=a[i];
Gcd[i][0]=a[i];
if(a[i]==1)flag=1;
}
if(flag==1)
{
printf("1 %d\n",n-1);
printf("1\n");
continue;
}
ST();
for(int i=1;i<=n;i++)
{
int L=-1;
int l=1;
int r=i;
while(r-l>=0)
{
int mid=(l+r)/2;
if(getminn(mid,i)==a[i])
{
L=mid;
r=mid-1;
}
else l=mid+1;
}
int R=-1;
l=i;
r=n;
while(r-l>=0)
{
int mid=(l+r)/2;
if(getminn(i,mid)==a[i])
{
R=mid;
l=mid+1;
}
else r=mid-1;
}
Slove(L,R,i);
}
printf("%d %d\n",ans.size(),maxn);
for(int i=0;i<ans.size();i++)
{
printf("%d ",ans[i]);
}
printf("\n");
}
}