题解:AT_abc352_d [ABC352D] Permutation Subsequence

虽然比赛没打,但是想来水估值发表思路。

题意

给你一个 \(1\sim n\) 的排列,让你从中找一段长为 \(k\) 的子序列,使得这个子序列中的元素排序后数值连续。

分析

题意转换一下,先用结构体存储每个元素的编号和数值,按照数值排序。

于是这道题就成了:一个序列,让你求所有长 \(k\) 的子段中每个段编号极差的最小值。

所以我们需要维护每个段编号最大最小值,我选择了 ST 表。

其他做法维护也有很多,这里就不讲了。

code

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
const int maxn=1e6+10;
int n,k;
struct no
{
	int d,id;
}a[maxn];
bool cmp(no x,no y)
{
	return x.d<y.d;
}
int ma[maxn][22],mi[maxn][22];
void pre()
{
	for(int j=1;j<=20;j++){
     	for(int i=1;i+(1<<j)-1<=n;i++)
			mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
	}
    for(int j=1;j<=20;j++){
     	for(int i=1;i+(1<<j)-1<=n;i++)
      		ma[i][j]=max(ma[i][j-1],ma[i+(1<<(j-1))][j-1]);
	}
	
}
int askmax(int l,int r)
{
	int le=l,ri=r;
        int len=log2(ri-le+1);
        return max(ma[le][len],ma[ri-(1<<len)+1][len]);
}
int askmin(int l,int r)
{
	int le=l,ri=r;
        int len=log2(ri-le+1);
		return min(mi[le][len],mi[ri-(1<<len)+1][len]);
}
signed main()
{
//  freopen("xxx.in","r",stdin);
//	freopen("xxx.out","w",stdout);
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		a[i].d=read();
		a[i].id=i;
	}
	sort(a+1,a+n+1,cmp);	
	for(int i=1;i<=n;i++)swap(a[i].d,a[i].id);
	for(int i=1;i<=n;i++)mi[i][0]=ma[i][0]=a[i].d;
	pre();
	int ans=1e9+7;
	for(int l=1;l<=n-k+1;l++)
	{
		int r=l+k-1;
		ans=min(ans,askmax(l,r)-askmin(l,r));
	}
	cout<<ans;
	return 0;
}

posted @ 2024-07-17 16:52  Redamancy_Lydic  阅读(12)  评论(0编辑  收藏  举报