【洛谷P1704】 寻找最优美做题曲线
自己YY的做法A了两道题了,十分开心,不过看到了我的做法居然和这道题的作者的作法一样,不太开心。。。
这道题就是在一个序列中让你选定一些数,再在必选这些数的基础上找出LIS。
我的做法挺鬼畜的。
首先对于一个要选定的点,我们可以排除一些绝对不会选的点。条件就是在当前点前面的点的值如果大于当前点,那么因为当前点必选,所以就可以排除那个前面的点,同样的,如果当前点后面的点的值小于当前点的值,那么我们也不选。
这样,我们就可以得到一个新的数组,在这个数组里直接求一遍LIS就行了。
刚刚自己想了一下,忽然感觉这个做法是错误的,因为我感觉在新数组里选LIS并没有保证原本要选的点一定被选。
但是并不是这样的,(机房一堆大佬反驳我。。。可是我说我的做法错他们反驳说对是什么鬼啊。。。)
我们可以这么想,对于一个一定要选的点,经过我们的处理,在这个点之前是一段全部小于他的数,后面是一段全部大于他的数,那么不管我们在这前后两段怎么选,都一定不会有一个数去替代他的位置,也就是说,我们可以用反证法证不选他不是最优的就可以了。
开心。
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int wx=500017;
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
int n,m,ans[wx],len,tot;
int flag[wx],a[wx],b[wx],f[wx],vis[wx];
int main(){
n=read();m=read();
for(int i=1,x;i<=m;i++)x=read(),flag[x]=1;
for(int i=1;i<=n;i++)a[i]=read();
int last=0;
for(int i=1;i<=n;i++){
if(a[i]>a[last])vis[i]=1;
if(flag[i])last=i;
}
last=n+1;a[n+1]=0x3f3f3f3f;
for(int i=n;i>=1;i--){
if(a[i]>a[last]&&flag[i]){
printf("impossible");return 0;
}
if(a[i]>a[last])vis[i]=0;
if(flag[i])last=i;
}
for(int i=1;i<=n;i++){
if(vis[i])b[++tot]=a[i];
}
ans[1]=b[1];len=1;
for(int i=2;i<=tot;i++){
if(b[i]>ans[len]){
ans[++len]=b[i];
}
else{
int pos=lower_bound(ans,ans+len,b[i])-ans;
ans[pos]=b[i];
}
}
printf("%d\n",len);
return 0;
}