题目传送门
题意:
给你一个长度为n的序列,我们要找到一个1<=i<=n,使得在[1,i]序列严格上升,[i,n]序列严格下降,找到这个最长的长度,输出没在这个序列中的数的个数。
思路一:O(n^2 logn)
很容易想到枚举n个点,采用二分nlogn的方法在[1,i]求一遍lis,反过来从n跑到i求lis,然后看长度。值得注意的是,应该以a[i]为基准,大于a[i]的不能放到序列中。
比如这组数据:
9 1 2 3 4 1 4 3 2 1
如果不注意这点,我们在5号点,求得前面的最长上升子序列长度为4,后面也是4,但是他们拼起来不能成为合法序列。所以我们通过这种方法求lis的时候要屏蔽大于a[i]的数。
思路二:O(n^2)
也就是最朴素的求lis,时间复杂度为n^2,这时候这种方法就比二分的方法要好,因为这个题用二分的方法需要屏蔽比a[i]大的数,而朴素版本不用考虑这个问题。(因为二者原理不同,二分法的d[i]表示的是如果长度为i,最优的结尾元素,而朴素lis求法的f[i]表示以第i个元素结尾能够获得的最优长度。)
二分:
#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ll long long
#define int long long
#define vi vector<int>
#define mii map<int,int>
#define pii pair<int,int>
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read(){int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
return x*f;}
using namespace std;
const int N=1e2+5;
const int inf=0x7fffffff;
const int mod=998244353;
const double eps=1e-6;
const double PI=acos(-1);
int a[N],d[N],n;
int up(int p)
{
memset(d,0,sizeof d);
int len=1;d[1]=a[1];
for(int i=1;i<p;i++)
{
if(a[i]>=a[p])
continue;
if(a[i]>d[len])
{
d[++len]=a[i];
}
else
{
int pos=lower_bound(d+1,d+len+1,a[i])-d;
d[pos]=a[i];
}
}
if(p==1)
len=0;
return len;
}
int down(int p)
{
memset(d,0,sizeof d);
int len=1;d[1]=a[p+1];
for(int i=p+1;i<=n;i++)
{
if(a[i]>=a[p])
continue;
if(a[i]<d[len])
d[++len]=a[i];
else
{
int pos=lower_bound(d+1,d+len+1,a[i],greater<int>())-d;
d[pos]=a[i];
}
}
if(p==n)
len=0;
return len;
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int res=0;
for(int i=1;i<=n;i++)
{
int len1=up(i);
if(d[len1]==a[i])
len1--;
int len2=down(i);
if(d[1]==a[i])
len2--;
res=max(res,len1+len2+1);
}
cout<<n-res<<endl;
}
朴素求法
#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ll long long
#define int long long
#define vi vector<int>
#define mii map<int,int>
#define pii pair<int,int>
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read(){int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
return x*f;}
using namespace std;
const int N=1e2+5;
const int inf=0x7fffffff;
const int mod=998244353;
const double eps=1e-6;
const double PI=acos(-1);
int a[N],dp[N][2],n;
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
dp[i][0]=1;
for(int j=1;j<i;j++)
{
if(a[i]>a[j])
dp[i][0]=max(dp[i][0],dp[j][0]+1);
}
}
for(int i=n;i>=1;i--)
{
dp[i][1]=1;
for(int j=n;j>i;j--)
{
if(a[i]>a[j])
dp[i][1]=max(dp[i][1],dp[j][1]+1);
}
}
int res=0;
for(int i=1;i<=n;i++)
{
res=max(res,dp[i][0]+dp[i][1]-1);
}
cout<<n-res<<endl;
}