3895. 【NOIP2014模拟10.26】数字对

63 篇文章 0 订阅
29 篇文章 13 订阅

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值