看到题目后,第一反应便是暴力枚举确定 \(i\)。但是看到了 \(N \le 2 \times 10^5\),这种想法便不合适了。观察题目第二个条件,不难发现其实真正合法的方案很少。于是可以转变方向,枚举题目要求的排列集合。
想到这步,接下来就不难了。确定好原排列中被选的数后,需要求出它们的下标的最小值和最大值。又由于这些数本身是连续的,因此可以用这些数作为下标,存储它们原先的下标。这样做就把这些下标集中在一起了,转换为区间最值查询问题,用各种数据结构维护即可。
以下采用 ST 表实现,时间复杂度 \(O( n \log n )\)。
#include <iostream>
#include <cstdio>
#include <cmath>
#define int long long
using namespace std;
int n,k,p,ans,a[1000001],st1[1000001][20],st2[1000001][20],lg[1000001];
void rd( void )
{
for( int j = 1 ; j <= 19 ; j ++ )
for( int i = 1 ; i + ( 1 << ( j - 1 ) ) <= n ; i ++ )
{
st1[i][j] = max( st1[i][j - 1] , st1[i + ( 1 << ( j - 1 ) )][j - 1] );
st2[i][j] = min( st2[i][j - 1] , st2[i + ( 1 << ( j - 1 ) )][j - 1] );
}
}
int query( int l , int r )
{
int d = lg[r - l + 1];
int ans1 = max( st1[l][d] , st1[r - ( 1 << d ) + 1][d] );
int ans2 = min( st2[l][d] , st2[r - ( 1 << d ) + 1][d] );
return abs( ans1 - ans2 );
}
signed main()
{
cin >> n >> k;
for( int i = 2 ; i <= n ; i ++ )
lg[i] = lg[i >> 1] + 1;
for( int i = 1 ; i <= n ; i ++ )
{
cin >> p;
a[p] = i;
st1[p][0] = st2[p][0] = i;
}
rd();
ans = n;
for( int i = 1 ; i + k - 1 <= n ; i ++ )
ans = min( ans , query( i , i + k - 1 ) );
cout << ans;
return 0;
}
标签:题目,int,1000001,abc352,下标,include
From: https://www.cnblogs.com/-lilong-/p/18199552