2024.1.21模拟赛 B题解

题目大意

思路

首先有一个50pts的网络流暴力

考虑按照\(dp\)值分层,发现在同一层内,随着\(i\)递增,\(a_i\)递减
由此可以进一步推出每一个点连接的出边,是下一层的一个区间,并且区间是单调的
于是可以线段树优化建边,拿到60pts

接着考虑模拟网络流,发现如果每次都选择第一条出边的话,就不会用到反悔边,于是直接模拟

code

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
int n,len,ans;
int a[N],b[N],pos[N],dp[N],vis[N],c[N];
vector<int> G[N];
int dfs(int x){
	if(vis[x]) return 0;
	vis[x]=1;
	if(dp[x]==len){
		ans++;return 1;
	}
	while(pos[dp[x]]<(int)G[dp[x]+1].size()&&G[dp[x]+1][pos[dp[x]]]<x) pos[dp[x]]++;
	while(pos[dp[x]]<(int)G[dp[x]+1].size()&&a[G[dp[x]+1][pos[dp[x]]]]>a[x]){
		int fl=dfs(G[dp[x]+1][pos[dp[x]]]);pos[dp[x]]++;
		if(fl) return 1;
	}
	return 0;
}
int lowbit(int x){
	return x&(-x);
}
void add(int x,int y){
	for(;x<=n;x+=lowbit(x)) c[x]=max(c[x],y);
}
int maxn(int x){
	int ans=0;
	for(;x;x-=lowbit(x)) ans=max(ans,c[x]);
	return ans;
}
int main(){
	freopen("lis.in","r",stdin);
	freopen("lis.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+1+n);
	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+n,a[i])-b;
	for(int i=1;i<=n;i++){
		dp[i]=maxn(a[i]-1)+1,len=max(len,dp[i]);
		G[dp[i]].push_back(i),add(a[i],dp[i]);
	}
	for(auto x:G[1]) dfs(x);
	printf("%d\n",n-ans);
	return 0;
}
posted @ 2024-01-21 21:07  hubingshan  阅读(16)  评论(0)    收藏  举报