[POI2007]堆积木Klo

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 530  Solved: 172
[Submit][Status]

Description

Mary在她的生日礼物中有一些积木。那些积木都是相同大小的立方体。每个积木上面都有一个数。Mary用他的所有积木垒了一个高塔。妈妈告诉Mary游戏的目的是建一个塔,使得最多的积木在正确的位置。一个上面写有数i的积木的正确位置是这个塔从下往上数第i个位置。Mary决定从现有的高塔中移走一些,使得有最多的积木在正确的位置。请你告诉Mary她应该移走哪些积木。

Input

输入文件的第一行为一个数n,表示高塔的初始高度。第二行包含n个数a1,a2,...,an,表示从下到上每个积木上面的数。(1<=n<=100000,1<=ai<=1000000)。

Output

注意:请输出最多有多少点可以处在正确位置

Sample Input

5

1 1 2 5 4

Sample Output

3

HINT

题解:

摘自:

BZOJ1109: [POI2007]堆积木Klo

先列下DP方程。令f[i]是第i个积木在自己的位置上时,前i个积木中最多能归位的数目。

f[i]=max{f[j]|i>j,a[i]>a[j],a[i]-a[j]<=i-j}+1

(无后效性和最优子结构都是可以保证的。统计答案的时候,每个f[]取一个mx)

其中a[i]>a[j]是保证i,j都在自己的位置上,a[i]-a[j]<=i-j是为了保证中间有足够的积木让i能在a[i]这个位置上。

为了让每个限制只和位置有关,a[i]-a[j]<=i-j可以变形为a[i]-i<=a[j]-j。

1:a[i]-i<=a[j]-j ===> -a[i]+i>=-a[j]+j

2:                                  a[i]>a[j]

得到i>j……说明只要满足a[i]>a[j]和a[i]-i<=a[j]-j,则一定满足i>j!

那么就只要按照a[i]-i排序(你想按照a[i]排序也行,那样两数相等就在求LIS的时候判了),求LIS即可。

由于a[i]-i相等时,a[i]升序就可以使答案最大化,所以排序的时候第二关键字要弄成a[i]。

(我们现在只要满足两个条件:

a[i]>a[j]

i-a[i]>=j-a[j]

在排好序的新数列中,最后的LIS就是最后剩下的归位的积木。

首先这样的选法肯定是合法的。因为下标和数值,可以满足这两个条件

并且这样肯定是最优的,对于每一个位置,会求一个前i位LIS,是最长的一个,并且,LIS的方程,f[i]=max(f[j],a[j]<a[i],j<i)+1

就满足了原来的DP方程。相当于从所有的合法转移中,选择了一个最大的。

实际上,LIS里的f数组,和我们开始的DP中的f数组,是同一个数组。本质意义是一样的。

因为,转移的条件一样,转移的方程也一样。

所以,两个f一样。

所以,这个变形是等价的。

代码:

(网上借鉴)

#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);
}

原文地址:https://www.cnblogs.com/Miracevin/p/9379800.html

时间: 2024-10-28 05:11:54

[POI2007]堆积木Klo的相关文章

【BZOJ1109】[POI2007]堆积木Klo 二维偏序

[BZOJ1109][POI2007]堆积木Klo Description Mary在她的生日礼物中有一些积木.那些积木都是相同大小的立方体.每个积木上面都有一个数.Mary用他的所有积木垒了一个高塔.妈妈告诉Mary游戏的目的是建一个塔,使得最多的积木在正确的位置.一个上面写有数i的积木的正确位置是这个塔从下往上数第i个位置.Mary决定从现有的高塔中移走一些,使得有最多的积木在正确的位置.请你告诉Mary她应该移走哪些积木. Input 第一行为一个数n,表示高塔的初始高度.第二行包含n个数

【bzoj1109】[POI2007]堆积木Klo 动态规划+树状数组

题目描述 Mary在她的生日礼物中有一些积木.那些积木都是相同大小的立方体.每个积木上面都有一个数.Mary用他的所有积木垒了一个高塔.妈妈告诉Mary游戏的目的是建一个塔,使得最多的积木在正确的位置.一个上面写有数i的积木的正确位置是这个塔从下往上数第i个位置.Mary决定从现有的高塔中移走一些,使得有最多的积木在正确的位置.请你告诉Mary她应该移走哪些积木. 输入 第一行为一个数n,表示高塔的初始高度.第二行包含n个数a1,a2,...,an,表示从下到上每个积木上面的数. 输出 注意:请

BZOJ1109 : [POI2007]堆积木Klo

f[i]表示第i个在自己位置上的最大值 则f[i]=max(f[j])+1 其中 j<i a[j]<a[i] a[i]-a[j]<=i-j -> j-a[j]<=i-a[i] i-a[i]>=0 j-a[j]>=0 发现后两项可以推出第一项,所以是一个LIS问题,排序后树状数组优化DP即可,时间复杂度$O(n\log n)$. #include<cstdio> #include<algorithm> #define N 100010 int

BZOJ 1109: [POI2007]堆积木Klo

Sol 排序+树状数组. 我们要找一个满足下列条件的最长序列. \(j-w[j]<=i-w[i],j<i,w[j]<w[i]\) 就是维护一个偏序集的最长上升子序列,然后第一个和第三个式子加起来可以推出第二个式子,然后就是二维偏序,用树状数组来维护就可以了. Code /************************************************************** Problem: 1109 User: BeiYu Language: C++ Result:

BZOJ 1109 POI2007 堆积木Klo LIS

题目大意:给定一个序列,可以多次将某个位置的数删掉并将后面所有数向左串一位,要求操作后a[i]=i的数最多 首先我们假设最后a[i]=i的数的序列为S 那么S满足随着i递增,a[i]递增(相对位置不变),i-a[i]单调不减(后面的不会比前面移动的少) 这是一个三维偏序问题 要是不看题解我就真去写CDQ分治了233 我们发现i=(i-a[i])+a[i] 也就是说如果一个序列满足i-a[i]单调不减且a[i]单调递增 那么i一定单调递增 于是就剩两维偏序了 LIS走起吧= = #include

Javascript异步编程之三Promise: 像堆积木一样组织你的异步流程

这篇有点长,不过干货挺多,既分析promise的原理,也包含一些最佳实践,亮点在最后:) 还记得上一节讲回调函数的时候,第一件事就提到了异步函数不能用return返回值,其原因就是在return语句执行的时候异步代码还没有执行完毕,所以return的值不是期望的运算结果. Promise却恰恰要回过头来重新利用这个return语句,只不过不是返回最终运算值,而是返回一个对象,promise对象,用它来帮你进行异步流程管理. 先举个例子帮助理解.Promise对象可以想象成是工厂生产线上的一个工人

2060 堆积木

2060 堆积木 2005年USACO 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 现在有N块积木,每块积木都有自重Weight和正常状态下的承重能力Force,现在要把这N块积木垒在一起,但是有可能某块积木的负重超过了它在正常状态下的承重能力,那么这块积木就有被压坏的危险,请问应该如何堆这N块积木使得N块积木中最大的压力指数最小. 这里定义压力指数为该积木的负重与其在正常状态下的承重能力的差值. 原题:Usaco N

堆积木----vector防止内存超限

蒜头君有 nn 块积木,编号分别为 11 到 nn.一开始,蒜头把第 ii 块积木放在位置 ii.蒜头君进行 mm 次操作,每次操作,蒜头把位置 bb 上的积木整体移动到位置 aa 上面.比如 11 位置的积木是 11,22 位置的积木是 22,那么把位置 22 的积木移动到位置 11 后,位置 11 上的积木从下到上依次为 1,21,2. 输入格式 第一行输入 22 个整数 n,m(1 \le n \le 10000, 0 \le m \le 10000)n,m(1≤n≤10000,0≤m≤1

[bzoj1109]堆积木

用f[i]表示前i个数,i必须被贡献的答案,考虑转移,枚举下一个被贡献的数j,那么j需要满足:1.$j<i$:2.$a[j]<a[i]$:3.$a[i]-(i-j+1)\le a[j]$,化简后即$j-a[j]\le i-a[i]$:4.$a[i]\le i$这是一个三维偏序,但发现第二个限制和第三个限制可以凑出第一个限制,即第一个限制和忽略,按照某一维排序,对另一维求lis即可(注意当$a[i]=a[j]$时要让i-a[i]逆序排序,来保证$a[j]<a[i]$ 1 #include&