• 洛谷 [P1020] 导弹拦截 (N*logN)


    首先此一眼就能看出来是一个非常基础的最长不下降子序列(LIS),其朴素的 N^2做法很简单,但如何将其优化成为N*logN?
    我们不妨换一个思路,维护一个f数组,f[x]表示长度为x的LIS的最大的最后一个数字是f[x]。(为什么是最大的?可以应用贪心的思想,发现对于相同的x,f[x]越大其后可能扩展的情况就越多,即就越优)我们可以发现f数组单调递减(为什么?也可使用反证法证明,在此不赘述)对于决策单调性问题,一般使用二分法优化,这就是logN的来历。二分的边界条件一定要写对。
    代码如下:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    int read(){
    	int rv=0,fh=1;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-') fh=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		rv=(rv<<1)+(rv<<3)+c-'0';
    		c=getchar();
    	}
    	return fh*rv;
    }//快读
    int num[100005],f[100005],q[100005];
    int find1(int x){
    	int l=1,r=f[0],m=0;
    	while(l<=r){
    		m=(l+r)>>1;
    		if(f[m]>=x){
    			l=m+1;
    		}else{
    			r=m-1;
    		}
    	}
    	//if(l<=f[0]) return l;
    	if(r>=1) return r;
    	return 0;
    }
    int find2(int x){
    	int l=1,r=f[0],m;
    	while(l<=r){
    		m=(l+r)>>1;
    		if(f[m]>=x){
    			r=m-1;
    		}else {
    			l=m+1;
    		}
    	}
    	if(r>=1) return r;
    	return 0;
    }
    int main(){
    	freopen("in.txt","r",stdin);
    	while(scanf("%d",&num[++num[0]])==1) ;
    	num[0]--;//一定要减
    	f[1]=num[1];f[0]++;
    	for(int i=2;i<=num[0];i++){
    		int pos=find1(num[i]); 
    		if(pos){
    			if(f[0]==pos) f[0]++;
    			f[pos+1]=max(f[pos+1],num[i]);
    			//cout<<f[pos+1]<<endl;
    		}else {
    			f[1]=max(f[1],num[i]);
    		}
    	}
    	cout<<f[0]<<endl;
    	for(int i=1;i<=f[0];i++){
    		f[i]=1000005;
    	}
    	f[0]=1;
    	f[1]=num[1];
    	for(int i=2;i<=num[0];i++){
    		int pos=find2(num[i]);
    		if(pos){
    			if(f[0]==pos) f[0]++;
    			f[pos+1]=min(f[pos+1],num[i]);
    		}else {
    			f[1]=min(f[1],num[i]);
    		}
    	}
    	cout<<f[0];
    	fclose(stdin);
    	return 0;
    }
    

    对于第二问,可使用dilworth定理,翻译成通俗易懂的语言就是:
    对于一个序列,其最少的不降子序列划分=最长上升子序列长度,所以对于第二问输出最长上升子序列长度即可。

  • 相关阅读:
    JZOI 4020 Revolution
    JZOJ 4018 Magic
    JZOJ 4017 逃跑
    JZOJ 4016 圈地为王
    JZOJ 4015 数列
    JZOJ 3960 鸡腿の出行
    BZOJ 5005 & JZOI 3959 鸡腿の乒乓
    GCJ2009B&JZOJ 4033 Min Perimeter
    jzoj 3948 Hanoi 塔
    [纯符][纯粹的无聊] 神奇的递推式
  • 原文地址:https://www.cnblogs.com/Mr-WolframsMgcBox/p/7868370.html
Copyright © 2020-2023  润新知