Description
小H是个善于思考的学生,现在她又在思考一个有关序列的问题。
她的面前浮现出一个长度为n的序列{ai},她想找出一段区间[L, R](1 <= L <= R <= n)。
这个特殊区间满足,存在一个k(L <= k <= R),并且对于任意的i(L <= i <= R),ai都能被ak整除。这样的一个特殊区间 [L, R]价值为R - L。
小H想知道序列中所有特殊区间的最大价值是多少,而有多少个这样的区间呢?这些区间又分别是哪些呢?你能帮助她吧。
Input
第一行,一个整数n.
第二行,n个整数,代表ai.
Output
第一行两个整数,num和val,表示价值最大的特殊区间的个数以及最大价值。
第二行num个整数,按升序输出每个价值最大的特殊区间的L.
Sample Input
输入1:
5
4 6 9 3 6
输入2:
5
2 3 5 7 11
Sample Output
输出1:
1 3
2
输出2:
5 0
1 2 3 4 5
Data Constraint
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.
Solution
多种解法,可以将a数组拍完序后,从小到大做,找出最左和最右可以延伸到的点,计算区间。正确性显然,时间复杂度显然O(n)
也可以直接从头到尾做,然后每次将i变成它最多向右能延伸到的点+1。正确性显然,时间复杂度玄学,却比上面做法快,O(n)。
Code1
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500010
using namespace std;
int n,l,r,ma,t,bz[N],ans[N],s[N];
struct node{int x,id;}a[N];
bool cmp(node a,node b){return a.x<b.x;}
void work(int o){
while(l){
bz[l]=1;
if(l-1>0&&s[l-1]%s[o]==0) l--;
else break;
}
while(r){
bz[r]=1;
if(r+1<=n&&s[r+1]%s[o]==0) r++;
else break;
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&s[i]);
a[i].x=s[i];
a[i].id=i;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
if(!bz[l=r=a[i].id]){
work(l);
if(r-l>ma){
ma=r-l;
t=0;
}
if(r-l==ma){
ans[++t]=l;
}
}
}
printf("%d %d\n",t,ma);
sort(ans+1,ans+1+t);
for(int i=1;i<=t;i++) printf("%d ",ans[i]);
return 0;
}
Code2
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500010
using namespace std;
int i,j,n,a[N],l,r,ma,tot,ans[N];
int main(){
ma=-1;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d",&a[i]);
i=0;
while(i<n){
i++;j=i;
while(j--){
if(j<=0||a[j]%a[i]!=0) break;
}
l=j+1;
j=i;
while(j++<=n){
if(j>n||a[j]%a[i]!=0) break;
}
r=j-1;
if(r-l>ma){
ma=r-l;
tot=0;
}
if(r-l==ma) ans[++tot]=l;
i=r;
}
printf("%d %d\n",tot,ma);
for(int i=1;i<=tot;i++) printf("%d ",ans[i]);
return 0;
}
作者:zsjzliziyang
QQ:1634151125
转载及修改请注明
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/86652286