题意:
给一串数,找出最长的区间使得这个区间里面有个数能被其他所有数整除(包括它自己),求满足这个条件的最长区间的个数及长度,以及这些区间的左端的位置
分析:
这个区间的要求其实就是GCD(ALL)=MIN(ALL),能被其他数整除,这个数肯定是最小的,然后又能被其他数整除(包括自己)这个数就是GCD了
可以二分枚举区间长度,然后验证答案的可靠性
对当前长度的所有区间,套用RMQ,验证是否存在一个区间的GCD=MIN
如果有这样的一个区间,那么说明当前长度可以,加大枚举的区间长度,否则减小
#include<iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include<cmath>
using namespace std;
#define MAXN 333333
int N;
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int num[MAXN];
int f1[MAXN][30];
int f2[MAXN][30];
void st(int n) {
int i, j, k, m;
k = (int) (log((double)n) / log(2.0));
for(i = 0; i < n; i++) {
f1[i][0] = num[i];
f2[i][0] = num[i];
}
for(j = 1; j <= k; j++) {
for(i = 0; i + (1 << j) - 1 < n; i++) {
m = i + (1 << (j - 1));
f1[i][j] = min(f1[i][j-1], f1[m][j-1]);
f2[i][j] = gcd(f2[i][j-1], f2[m][j-1]);
}
}
}
//查询i和j之间的最值,注意i是从0开始的
int rmq_gcd(int i, int j) {
int k = (int)(log(double(j-i+1)) / log(2.0)), t2;
t2 = gcd(f2[i][k], f2[j - (1<<k) + 1][k]);
return t2;
}
int rmq_min(int i, int j) {
int k = (int)(log(double(j-i+1)) / log(2.0)), t1;
t1 = min(f1[i][k], f1[j - (1<<k) + 1][k]);
return t1;
}
bool check(int l){
for(int i=0;i<N && i<=N-l;i++){
if(rmq_gcd(i,i+l-1)==rmq_min(i,i+l-1))
return true;
}
return false;
}
vector<int>ans;
void get(int l){
for(int i=0;i<N && i<=N-l;i++){
if(rmq_gcd(i,i+l-1)==rmq_min(i,i+l-1))
ans.push_back(i+1);
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("/home/rainto96/in.txt","r",stdin);
#endif
int i;
scanf("%d", &N);
for (i = 0; i < N; i++) {
scanf("%d", num+i);
}
st(N);
int l=1,r=N,mid=(l+r)/2+1;
while(l<r){
if(check(mid))l=mid;
else r=mid-1;
mid=(l+r)/2+1;
}
get(l);
cout<<ans.size()<<' '<<l-1<<endl;
for(int i=0;i<ans.size();i++){
cout<<ans[i]<<' ';
}
cout<<endl;
return 0;
}