题解:
首先:我们可以推出答案一定是最大数的约数
然后,我们就可以先暴力枚举出最大值的约数
再,判断其是否可行
其方法是: 分治
find ( l , r , num ) 为在 l ~ r 这段区间之内最多分成几段
那就先找 1 ~ n 这段区间的最大值,然后看其是否可以整除 num
若可,再在其左边及右边找一下即可
若不可,则也就是说要将其与另一个比它更大的数合并
当然这个过程有很多小细节,如:( 在不可整除的情况下 )
- 当 l 为 1 时,则这个数必须与右边合并
- 当 r 为 n 时,则这个数必须与左边合并
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#define LL long long
#define ull unsigned LL
#define db double
#define ldb long db
#define INF 1000000009
using namespace std;
const int N=1e6+100,M=1010;
int n,m,wz,maxn,k,a[N],s[N];
int find ( int l,int r )
{
int wz=0,maxn=0;
for ( int i=l;i<=r;i++ ) if ( a[i]>maxn ) maxn=a[i],wz=i;
return wz;
}
int pd ( int l,int r,int num )
{
if ( l>r ) return 0;
int wz=find ( l,r );
if ( a[wz]%num==0 ) return pd ( l,wz-1,num ) + pd ( wz+1,r,num ) + 1;
if ( l==1 ) return pd ( l,wz-1,num );
if ( r==n ) return pd ( wz+1,r,num );
return max ( pd ( l,wz-1,num ),pd ( wz+1,r,num ) );
}
int main ( )
{
scanf ( "%d %d",&n,&k );
for ( int i=1;i<=n;i++ ) scanf ( "%d",&a[i] ),maxn=max ( maxn,a[i] );
for ( int i=1;i<=maxn/i;i++ )
{
if ( i*i==maxn ) s[++m]=i;
else if ( maxn%i==0 ) s[++m]=i,s[++m]=maxn/i;
}
sort ( s+1,s+1+m );
for ( int i=m;i>=1;i-- ) if ( pd ( 1,n,s[i] )>=k ) { printf ( "%d",s[i] );break; }//printf ( " %d\n",pd ( 1,n,s[i] ) );
return 0;
}
最后其实还有一个优化:
查询 l ~ r 的最大值可以用RMQ
但我看了看数据还可以撑过去,就咳咳了