BZOJ 1109 [POI2007]堆積木Klo DP

題意:

給定一個序列A,刪除任意個數的數,使得生成的新序列B={a,b,c,d….}與序列C={1,2,3,4…..}一一對應的數的個數最多,求最多能對應多少個數。


解析:

不妨列一下樸素的DP方程

f[i]=max(f[j]+1)(j<ia[j]<a[i]a[i]a[j]<=ij)

複雜度O(n^2),顯然不可過,所以需要進一步優化。
觀察三個限定條件。
1j<i
2a[j]<a[i]
3a[i]a[j]<=ijja[j]<=ia[i]
容易發現已知2,3 可以推出1
1 代表的是這n 個數的排列順序。
2 的條件即爲最長上升子序列。
所以我們不妨把3 看做這n 個數的重新排列法則,之後滿足2 的條件即可。
所以我們只需要按照ja[j]<=ia[i]n 個數重新排列,接着求一個最長上升子序列長度即可。
需要注意的是,如果ia[i]<0 的話,那麼顯然這個數不可能與C序列中的某個數對應上,直接跳過即可。

代碼:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100100
#define M 1000100
using namespace std;
struct node
{
    int x,y;
    friend bool operator < (node a,node b)
    {
        if(a.x==b.x)return a.y<b.y;
        return a.x<b.x;
    }
}b[N];
int d[M],a[N];
int n,ma,tot;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(i-a[i]<0)continue;
        b[++tot].x=i-a[i],b[tot].y=a[i];
    }
    sort(b+1,b+tot+1);
    memset(d,0x3f,sizeof(d)); 
    for(int i=1;i<=tot;i++)
    {
        int l=1,r=ma,ans=0;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(b[i].y>d[mid])ans=mid,l=mid+1;
            else r=mid-1;
        }
        ma=max(ma,ans+1);
        d[ans+1]=min(d[ans+1],b[i].y);
    }
    printf("%d\n",ma);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章