5 条题解

  • 0
    @ 2025-11-5 16:45:00

    首先我们发现我们要对于每一个数找到其左边右边第一个不能整除的数

    找每个数左边右边第一个比其大和比其小的时候都使用单调栈,所以这道题考虑使用单调栈

    这个单调栈里面的数需满足:相邻两个数之间呈倍数关系。入栈的时候若不满足,就弹出栈顶,直到满足。

    因此,一个数被谁弹出栈,它右侧第一个它不能整除的数就是谁

    正着反着跑两遍即可。

    目前最优解

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #include<stack>
    #define N 300005
    using namespace std;
    bool Test_MLE_start;
    int _=1,n,cnt=0,ans=0,top=0,a[N],L[N],R[N],p[N],stk[N];
    //stack<int> stk;
    inline int reads(){
    //	char buf[1<<20],*p1,*p2;
    //	#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
    	int c=getchar(),x=0,f=1;
    	while(!isdigit(c)) c=getchar_unlocked(); 
    	while(isdigit(c)){x=(x<<3)+(x<<1)+(c^48);c=getchar_unlocked();}
    	return x*f;
    }inline void files(){
    	freopen("A.in","r",stdin);
    //	freopen("std.ans","w",stdout);
    }inline void clr(){
    //	Don't forget!
    
    }int gcd(int a,int b){return b?gcd(b,a%b):a;}
    bool Test_MLE_end;
    signed main(){
    //	printf("%lf Mb\n",(&Test_MLE_end-&Test_MLE_start-1)/1024.0/1024.0);
    //	files();
    //	_=reads();
    	while(_--){
    		clr();n=reads();
    		for(int i(1);i<=n;i++) a[i]=reads();
    		for(int i(1);i<=n;i++){
    			while(top&&(a[stk[top]]>a[i]||a[i]%a[stk[top]]!=0)) R[stk[top--]]=i;
    			stk[++top]=i;
    		}while(top) R[stk[top--]]=n+1;
    		for(int i(n);i>=1;i--){
    			while(top&&(a[stk[top]]>a[i]||a[i]%a[stk[top]]!=0)) L[stk[top--]]=i;
    			stk[++top]=i;
    		}while(top) L[stk[top--]]=0;
    		for(int i(1);i<=n;i++){
    			if(R[i]-L[i]-1>ans){
    				ans=R[i]-L[i]-1;
    				p[cnt=1]=L[i]+1;
    			}else if(R[i]-L[i]-1==ans&&p[cnt]!=L[i]+1) p[++cnt]=L[i]+1;
    		}printf("%d %d\n",cnt,ans);
    		for(int i=1;i<=cnt;i++) printf("%d ",p[i]);
    	}exit(0);
    }
    /*
    14
    61 30 28 31 23 28 54 56 24 12 28 54 47 67 
    */
    

    信息

    ID
    571
    时间
    1000ms
    内存
    256MiB
    难度
    8
    标签
    (无)
    递交数
    121
    已通过
    20
    上传者