题解——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
*/