题解——NYG的动态数点

题解——NYG的动态数点( 栈的应用 )

*这道题题解是 nlog^2的,实际上完全没必要,ssw02考场打了个稳定 O( n )把这道题‘水’过了 *


题面

Description

然后私有题面隐藏了

Input
一个数N
N个数ai

Output
最大的个数,价值,以及左端点位置

in.1
5
4 6 9 3 6

out.1
1 3
2

数据范围与约定

N<= 5e5 , Ai <= 2^32

思路

主要思路

Doggu大佬曾经讲过用栈来处理 1e8 范围的扩展性最小值问题 , 这道题也差不多。

性质1:合法的值一定是这个区间的最小值

性质2:合法区间具有连续性

由上面2个性质,我们很容易想到,用一个栈来维护。

定义 head 为当前真实影响的栈最优顶值(因为下面 1 情况没有出栈)。

我们分为3种情况。

1.新压上来的数可以被 head 所指的数整除,我们不把他出栈,放在栈顶,并且让 head 所指值得贡献增加。

2.新压上来的数可以整除 head 所指的数,那这个数一定更优,不断弹栈并且累加该值的贡献。

3.同时不满足上面2种,那么区间连续性中断,head记录为当前该值。

细节

注意有的不是贡献++,而是贡献+=被弹出的值的贡献(自己思考咯,ssw02懒得讲喽)

复杂度

每个值仅仅会入栈一次,出栈小于等于1次,中途所有细节都仅仅涉及单值查询。复杂度严格 O(n)

外加ssw02考试写丑了,但时间还是是最快的。

考试时定义变量重了,就用 son 记录了贡献 , val 记录了原值

#include<bits/stdc++.h>
using namespace std ;
const int MAXN = 500005 ;
#define ll long long
inline int read(){
	int s=0 ; char g=getchar() ; while(g>'9'||g<'0')g=getchar() ; 
	while(g>='0'&&g<='9')s=s*10+g-'0',g=getchar() ; return s ;
}
struct Seg{// 稳定的 O(n)做法 
	ll num , val , l , r , son  ;//作者ssw02:下面的那个可以改成 + t[ u ].l 自己想,实际都一样的
}t[ MAXN ] ;
stack<int>q ;
int N , M , head = 0 , opt[ MAXN ] , op = 0 ; 
int main(){
	freopen("point.in","r",stdin);
	freopen("point.out","w",stdout);
	N = read() ; if( N == 1 ){cout<<1<<" "<<0<<endl<<1;} 
	for( int i = 1 ; i <= N ; ++i ){
		t[ i ].val = read() , t[ i ].num = i , t[ i ].l =  t[ i ].r = 0 ;
		if( q.empty() ){ q.push(i) ; head = i ; }
		else{
			if( t[ i ].val % t[ head ].val == 0 ){
				t[ head ].r++ ; q.push(i ) ;
			}
			else if( t[ head ].val % t[ i ].val == 0 ){//要命 
				while( q.top() != head ){
					q.pop() ; t[ i ].l++ ;
				}
				t[ i ].l += t[ head ].l+1 ; q.pop() ;
				while( !q.empty() ){
					int u = q.top() ; 
					if( t[ u ].val % t[ i ].val != 0 )break ;
					q.pop() ; t[ i ].l += t[ u ].l + 1 ; 
				}
				q.push(i) ; head = i ;
			}
			else if( t[ i ].val % t[ head ].val != 0 ){
				while( q.top() != head ){
					int u = q.top() ; 
					if( t[ u ].val % t[ i ].val != 0 )break ;
					q.pop() ; t[ i ].l++ ; 
				}
				head = i ; q.push( i ) ;
			}
		}
	}
	for( int i = 1 ; i <= N ; ++i )t[ i ].son = t[ i ].l + t[ i ].r;
	//for( int i = 1 ; i <= N ; ++i )cout<<t[ i ].son<<" ";
	ll ans1 = -1  ; 
	for( int i = 1 ; i <= N ; ++i ){
		if( t[ i ].son == ans1 )
			opt[ ++op ] = i - t[ i ].l ;
		if( t[ i ].son > ans1 ){
			ans1 = t[ i ].son , op = 1 , opt[ op ] = i - t[ i ].l ;
		}
	}
	cout<<op<<" "<<ans1<<endl ;
	for( int i = 1 ; i <= op ; ++i  )
		printf("%d ",opt[ i ] ) ;
	return 0 ;
}
/*
30
15 15 3 30 9 30 27 11 5 15 20 10 25 20 30 15 30 15 25 5 10 20 7 7 16 2 7 7 28 7
*/

如有不足,请大佬指出

posted @ 2019-09-16 16:47  蓝银杏-SSW  阅读(3270)  评论(0编辑  收藏  举报
//结束