BNUOJ49098 神奇的身高 - DP (LIS)
2015-12-29 11:04
281 查看
Time Limit: 2000ms Memory Limit: 65536KB
有一群小伙伴站成一行,每个人的身高都是非负整数,但是他们站在一起并不和谐。需要将他们的身高变成严格单调递增的正整数序列才是和谐的。现在你有一种神奇的魔法,可以任意改变一个人的身高。现在问题来了,你最少需要改变多少人的身高才能使整个队伍和谐。(改变后的身高必须为整数)
每组测试数据:
第1行:一个数n表示人数(1≤n≤100000)
第2~n+1行:每行1个数,对应数组的元素(0≤A[i]≤10^9)
以EOF结束
分析这个问题会自然地想到最长递增子序列(Longest Increasing Subsequence),因为不需要修改的人组成的序列肯定是这样一个序列。
但是经过分析,我们并不能通过直接求出原序列的LIS长度用总长度减去它来得到答案,这是因为原序列的LIS可能会含有这类情况:
1,1,2,3 虽然最长的LIS长度为3,但是我们不能只把一个1改为2,因为它遇到了“相等”这一情况,修改后身高不是严格递增的。
这会让我们思考如何求一个与原序列有关,其LIS的情况哪怕是遇到“相等”也满足修改后原序列严格递增的。
一个容易想到的情况是,把序列中的所有数减去一个单调递增的序列得到新序列,这个新序列中,即便修改后遇到相等,加上原来的递增数列,原序列依旧严格递增
那么,我们应该减去什么序列呢?分析原题,我们不难发现完美的身高序列中每个人的身高都要大于其所占位置(从0开始计数)的序号,
判断条件即减去从1开始的正整数列,小于等于零的消去(这些身高必然要修改),这部分人数暂记为ans,把结果大于零的输入一个新数列,这个新数列的LIS就是不需要修改的那些值;新数列总人数为tot,现在需要求的是它的每个元素减去下标后的最长上升子序列(LIS)长度dnum,利用动态规划就能实现
最后的答案是ans=ans+tot-dnum
有一群小伙伴站成一行,每个人的身高都是非负整数,但是他们站在一起并不和谐。需要将他们的身高变成严格单调递增的正整数序列才是和谐的。现在你有一种神奇的魔法,可以任意改变一个人的身高。现在问题来了,你最少需要改变多少人的身高才能使整个队伍和谐。(改变后的身高必须为整数)
Input
有多组测试数据,保证大数据不超过15组。每组测试数据:
第1行:一个数n表示人数(1≤n≤100000)
第2~n+1行:每行1个数,对应数组的元素(0≤A[i]≤10^9)
以EOF结束
Output
输出最少需要修改几人的身高才能使整个队伍和谐。Sample Input
2 1 2 2 2 1
Sample Output
0 1
分析这个问题会自然地想到最长递增子序列(Longest Increasing Subsequence),因为不需要修改的人组成的序列肯定是这样一个序列。
但是经过分析,我们并不能通过直接求出原序列的LIS长度用总长度减去它来得到答案,这是因为原序列的LIS可能会含有这类情况:
1,1,2,3 虽然最长的LIS长度为3,但是我们不能只把一个1改为2,因为它遇到了“相等”这一情况,修改后身高不是严格递增的。
这会让我们思考如何求一个与原序列有关,其LIS的情况哪怕是遇到“相等”也满足修改后原序列严格递增的。
一个容易想到的情况是,把序列中的所有数减去一个单调递增的序列得到新序列,这个新序列中,即便修改后遇到相等,加上原来的递增数列,原序列依旧严格递增
那么,我们应该减去什么序列呢?分析原题,我们不难发现完美的身高序列中每个人的身高都要大于其所占位置(从0开始计数)的序号,
判断条件即减去从1开始的正整数列,小于等于零的消去(这些身高必然要修改),这部分人数暂记为ans,把结果大于零的输入一个新数列,这个新数列的LIS就是不需要修改的那些值;新数列总人数为tot,现在需要求的是它的每个元素减去下标后的最长上升子序列(LIS)长度dnum,利用动态规划就能实现
最后的答案是ans=ans+tot-dnum
#include <iostream> #include <algorithm> #include <cstdio> using namespace std; const int maxn = 1e5+10; int a[maxn]; int b[maxn]; int dp[maxn]; int main() { int n; while(~scanf("%d",&n)) { int num=0,ans=0,tot=0; for(int i=0;i<n;i++) { scanf("%d",&a[i]); a[i]-=i; if(a[i]<1){ ans++; } else{ b[tot++]=a[i]; } } int dnum=0; for(int i=0;i<tot;i++) { int pos = upper_bound(dp,dp+dnum,b[i])-dp; if(pos==dnum) dp[dnum++]=b[i]; else dp[pos]=b[i]; } ans=ans+tot-dnum; printf("%d\n",ans); } return 0; }
相关文章推荐
- [转]CocoaPods的安装使用和常见问题
- Linux的分区方法
- 刷新实现原理
- Android sdk content loader 0%的解决方案
- 在iOS 8中使用UIAlertController
- locate包的安装
- ahjesus Axure RP 7.0注册码
- swift 函数创建
- JSON服务器的使用和客户端的解析
- EF学习笔记——通用增删改查方案
- 旋转转盘选择Menu--第三方开源--CircleMenu
- PopupWindow的简单使用
- ListView嵌套ListView的思路
- gpg: no valid OpenPGP data found
- 图片居中显示
- Jinx项目2015-12-29日记
- fragment切换 hide和show之后重新刷新数据的方法
- PHPWIND二次开发环境
- nyoj 素数环
- 如何判定一个变量是指针还是非指针