问一个n元序列任删掉一段m长的子段后的LIS长度
n1e5,考虑枚举剩下的右端点参与答案贡献,我们需要右端点开始的LIS,以及删除段左边的,刚好比右端点小的点往前跑的LIS
前者可以去个负倒过来跑一下,后者双针边跑边更新就行
//#include<bits/stdc++.h> //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<algorithm> #include<queue> #include<string.h> #include<iostream> #include<math.h> #include<set> #include<map> #include<vector> #include<iomanip> using namespace std; const double pi=acos(-1.0); #define ll long long #define pb push_back #define sqr(a) ((a)*(a)) #define dis(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)) #define FOR(a) for(int i=1;i<=a;i++) const double eps=1e-10; const int maxn=1e5+56; const int inf=0x3f3f3f3f; int a[maxn],b[maxn],dp[maxn],f[maxn]; int main(){ int T;scanf("%d",&T); int kase=0; while(T--){ int n,m;scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); b[i]=-a[i]; } memset(dp,0x3f,sizeof dp); for(int i=n;i>=1;i--){ int t=lower_bound(dp+1,dp+1+n,b[i])-dp; f[i]=t; //i开头的最长长度 dp[t]=b[i]; } memset(dp,0x3f,sizeof dp); int ans=0; for(int i=m+1;i<=n;i++){ //枚举右端点 int t=lower_bound(dp+1,dp+1+n,a[i])-dp; ans=max(ans,t-1+f[i]); *lower_bound(dp+1,dp+1+n,a[i-m])=a[i-m]; } //在求左边lis过程中找右端点的lb int t=lower_bound(dp+1,dp+1+n,inf)-dp;//全左 ans=max(ans,t-1); printf("Case #%d: %d ",++kase,ans); } }