bzoj1109:[POI2007]堆积木Klo

传送门

自己想的方向一直是对的,但是一直没有完全正确
我一直没发现可以缩掉一维
原本列出的dp方程是这样的
\(f[i]=f[j]+1(j<i\&\&a[j]<a[i]\&\&j-a[j]<=i-a[i])\)\(f[i]\)代表\(i\)移动到正确位置,前\(i\)个最多有多少个到正确位置)
看着就是lis,实际上想也可以想得到lis是最优的
然后你会发现满足后两个要求就满足了第一个要求,那么我们就可以按照\(i-a[i]\)排序,然后做lis就行了
PS.不可能移动到原位的显然不用考虑,判掉就行了
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
void read(int &x) {
    char ch; bool ok;
    for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define rg register
#define lowbit(i) (i&(-i))
const int maxn=1e6+10;
int n,f[maxn],ans,mx,now;struct oo{int x,id;}a[maxn];
void add(int x,int y){for(rg int i=x;i<=mx;i+=lowbit(i))f[i]=max(f[i],y);}
int get(int x){int ans=0;for(rg int i=x;i;i-=lowbit(i))ans=max(ans,f[i]);return ans;}
bool cmp(oo x,oo y){return x.id==y.id?x.x<y.x:x.id<y.id;}
int main()
{
    read(n);
    for(rg int i=1;i<=n;i++)read(a[i].x),a[i].id=i-a[i].x,mx=max(mx,a[i].x);
    sort(a+1,a+n+1,cmp);
    for(rg int i=1;i<=n;i++)if(a[i].id>=0)now=get(a[i].x-1)+1,ans=max(ans,now),add(a[i].x,now);
    printf("%d\n",ans);
}

猜你喜欢

转载自www.cnblogs.com/lcxer/p/10409321.html