题解:P7804 [JOI Open 2021] 决算报告 / Financial Report
EchoHua0402 · · 题解
题意
由于本题题面描述过于抽象,所以先来翻译一下题意。
给出一个长为
做法
在下文中,称“关键元素”为在子序列中满足
首先考虑设
现在考虑“相邻两项在原序列中的位置的差
证明省略,比较简单,读者可以尝试自己证一下。
通过进一步思考,发现合法的
为了“去除”掉大小的限制,我们先按
可以弄一个 set 用来维护已经更新过的
于是我们就获得了做法:排序后,从小到大更新
代码
个人认为还是比较具有可读性的:
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,D,ans=0,fa[N];
struct F{int x,id;}a[N];
bool cmp(F a,F b) {return a.x==b.x?a.id>b.id:a.x<b.x;}
struct Node{int l,r,mx;}tree[N<<2];
void pushup(int p) {tree[p].mx=max(tree[p*2].mx,tree[p*2+1].mx);}
void build(int p,int l,int r) {
tree[p].l=l,tree[p].r=r,tree[p].mx=0;
if (l==r) return ;
int mid=(l+r)>>1;
build(p*2,l,mid); build(p*2+1,mid+1,r);
}
void modify(int p,int x,int k) {
if (tree[p].l==tree[p].r) {tree[p].mx=max(tree[p].mx,k); return ;}
int mid=(tree[p].l+tree[p].r)>>1;
if (x<=mid) modify(p*2,x,k);
else modify(p*2+1,x,k);
pushup(p);
}
int query(int p,int l,int r) {
if (l<=tree[p].l&&tree[p].r<=r) return tree[p].mx;
int mid=(tree[p].l+tree[p].r)>>1,res=0;
if (l<=mid) res=max(res,query(p*2,l,r));
if (r>mid) res=max(res,query(p*2+1,l,r));
return res;
}
inline int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
inline void Merge(int u,int v) {
int fu=find(u),fv=find(v);
fa[max(fu,fv)]=min(fu,fv);
}
int main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>D; build(1,1,n);
for (int i=1;i<=n;i++) cin>>a[i].x,a[i].id=i,fa[i]=i;
sort(a+1,a+n+1,cmp); set<int> now;
for (int i=1;i<=n;i++) {
int id=a[i].id; now.insert(id);
auto p=now.find(id);
int lst=(p!=now.begin()?(*prev(p)):-1),nxt=(next(p)!=now.end()?(*next(p)):-1);
if (lst!=-1&&id-lst<=D) Merge(lst,id);
if (nxt!=-1&&nxt-id<=D) Merge(id,nxt);
int dp=query(1,find(id),id)+1; ans=max(ans,dp);
modify(1,id,dp);
}
cout<<ans<<"\n";
return 0;
}