https://www.luogu.org/problemnew/show/P1020

第一问就是最长不上升子序列,第二问题解说用离散数学里的Dilworth定理,看不懂证明,它的结论是:将序列划分若干个为不上升子序列,使得划分的个数最小,那么这个个数等于序列的最长上升子序列的大小。

#include<bits/stdc++.h>
using namespace std;

int n;

int d[100005];
int L=1,R=0;

int d2[100005];

int binary(int v)
{
    int l=L,r=R,m;
    while(l<r)
    {
        m=(l+r)/2;
        if(d[m]>=v)l=m+1;
        else r=m;
    }    
    return r;
}

int main()
{
//	freopen("input.in","r",stdin);
    fill(d,d+100005,-(1<<30)); 
    fill(d2,d2+100005,(1<<30));


    while(cin>>n)
    {    
        R++;    
        int pos=binary(n);  
        d[pos]=n;   
        
        *lower_bound(d2+1,d2+R+1,n)=n;      
    }      
    for(int i=R;i>=L;i--)if(d[i]!=-(1<<30))
    {
        cout<<i<<endl;
        break;
    }
    for(int i=R;i>=L;i--)if(d2[i]!=(1<<30))
    {
        cout<<i<<endl;
        break;
    }
    return 0;
}

 

木棍加工  https://www.luogu.org/problemnew/show/P1233

这道题不能直接做,因为木棍的顺序可以打乱。

因此以长度为第一关键字,宽度为第二关键字,降序排列。然后就不用考虑长度了,只考虑宽度,可以用那个定理,最少的不上升子序列的划分数等于最长上升子序列的长度。

忘了o(nlogn)了,写了o(n^2)的

#include<bits/stdc++.h>
using namespace std;

int n,l[5005],w[5005],d[5005],idx[5005];

bool cmp(int i,int j)
{
	if(l[i]!=l[j])return l[i]>l[j];
	return w[i]>w[j];
}

int main()
{
//	freopen("input.in","r",stdin);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>l[i]>>w[i];
	for(int i=1;i<=n;i++)idx[i]=i;
	sort(idx+1,idx+1+n,cmp);
	for(int i=n;i>0;i--)
	{
		int maxn=0;
		for(int j=i+1;j<=n;j++)if(w[idx[j]]>w[idx[i]])maxn=max(maxn,d[idx[j]]);
		d[idx[i]]=maxn+1;
	}
	int maxn=0;for(int i=1;i<=n;i++)maxn=max(maxn,d[i]);
	cout<<maxn<<endl;
	return 0;
 }