山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj 1109 [POI2007]堆积木Klo(LIS)

 

【题意】

 

    n个数的序列,删除一个数后序列左移,求最后满足i==a[i]的最大个数。

 

【思路】

   

    设最终得到a[i]==i的序列为s,则s应满足:

        i<j,a[i]<a[j],i-a[i]<=j-a[j]

  最后一项代表后边的移动距离不少于前边的。

    因为i=i-a[i]+a[i]

    所以只要满足i-a[i]单调不减,a[i]单调递增则i一定递增。

    则问题转化为一个二维偏序问题,O(nlogn)求LIS。用个BIT即可。

 

【代码】

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 typedef long long ll;
 8 const int N = 2e5+10;
 9 
10 struct Node {
11     int a,b;
12     bool operator <(const Node& rhs) const {
13         if(a!=rhs.a) return a<rhs.a;
14         else return b<rhs.b;
15     }
16 }ns[N];
17 
18 int C[N],mx;
19 void upd(int x,int v) {
20     for(;x<=mx;x+=x&-x) 
21         C[x]=max(C[x],v);
22 }
23 int query(int x) {
24     int res=0;
25     for(;x;x-=x&-x) 
26         res=max(res,C[x]);
27     return res;
28 }
29 
30 ll read() {
31     char c=getchar(); ll f=1,x=0;
32     while(!isdigit(c)) {
33         if(c=='-') f=-1;
34         c=getchar();
35     }
36     while(isdigit(c))
37         x=x*10+c-'0',
38         c=getchar();
39     return x*f;
40 }
41 
42 int n,a[N];
43 
44 int main()
45 {
46     //freopen("klo.in","r",stdin);
47     //freopen("klo.out","w",stdout);
48     n=read();
49     int tot=0;
50     for(int i=1;i<=n;i++) {
51         a[i]=read();
52         mx=max(mx,a[i]);
53         if(i>=a[i])
54             ns[++tot].a=i-a[i],ns[tot].b=a[i];
55     }
56     sort(ns+1,ns+tot+1);
57     int ans=0;
58     for(int i=1;i<=tot;i++) {
59         int x=query(ns[i].b-1)+1;
60         ans=max(ans,x);
61         upd(ns[i].b,x);
62     }
63     printf("%d\n",ans);
64     return 0;
65 }

 

P.S.感觉挺巧妙的 %%%

 

posted on 2016-03-19 19:12  hahalidaxin  阅读(331)  评论(0编辑  收藏  举报