本题就是一题LIS(最长递增子序列)的问题。本题要求求最长递增子序列和最长递减子序列。

dp的解法是O(n*n),这个应该大家都知道。只是本题应该超时了。

由于有O(nlgn)的解法。

可是因为本题的数据特殊性。故此本题能够利用这个特殊性加速到O(n)的解法。当中的底层思想是counting sort分段的思想。就是假设你不会counting sort的话,就非常难想出这样的优化的算法了。

O(nlgn)的利用单调队列性质的解法,利用二分加速是有代表性的,无数据特殊的时候也能够使用。故此这里先给出这个算法代码。

看了代码就知道非常easy的了,只是这里为了更加高效利用代码,就使用了函数指针,代码十分简洁了,刚開始学习的人耐心点看,代码应该非常好的:

#include <stdio.h>

const int MAX_N = 30000;
int arr1[MAX_N], arr2[MAX_N];
inline int max(int a, int b) { return a > b? a : b; } inline bool larEqu(int a, int b) { return a <= b; }
inline bool smaEqu(int a, int b) { return a >= b; } int biSearch(int low, int up, int val, bool (*func)(int , int))
{
while (low <= up)
{
int mid = low + ((up-low)>>1);
if (func(val, arr2[mid])) low = mid+1;
else up = mid-1;
}
return low;
} int getLIS(int n, bool (*func)(int, int))
{
int j = 0;
arr2[0] = arr1[0];
for (int i = 1; i < n; i++)
{
if (func(arr1[i], arr2[j])) arr2[++j] = arr1[i];
else arr2[biSearch(0, j, arr1[i], func)] = arr1[i];
}
return j+1;
} int main()
{
int n;
while (scanf("%d", &n) != EOF)
{
for (int i = 0; i < n; i++)
{
scanf("%d", &arr1[i]);
}
printf("%d\n", n-max(getLIS(n, larEqu), getLIS(n, smaEqu)));
}
return 0;
}

然后是O(n)的时间效率的算法。

就是由于仅仅有1,2,3,这三个数据,故此能够分开窗体。分别记录1。 2, 3 的数据段,在利用上面单调队列的思想的时候,就能够不使用二分法了,而是直接插入就能够了,故此省去了lgn的时间。时间效率就优化到O(n)了。

这个算法卡了我的地方就是下标的问题,老是无法准确记录窗体下标的,故此这里使用个特殊的记录下标的方法。看代码就好像是个O(n*n)的算法。由于循环中有循环。可是大家细致看,事实上这是个O(n)算法。为什么呢?由于循环中的循环总共仅仅是搜索了一遍n个数。无需反复搜索。

#include <stdio.h>

const int MAX_N = 30000;
int arr1[MAX_N], arr2[MAX_N];
inline int max(int a, int b) { return a > b? a : b; } int getLIS(int n)
{
int j = 0, one = 0, two = 0;
arr2[0] = arr1[0];
for (int i = 1; i < n; i++)
{
if (arr1[i] >= arr2[j])
{
arr2[++j] = arr1[i];
}
else
{
if (arr1[i] == 1)
{
while (arr2[one] < 2 && one < j) one++;
arr2[one] = arr1[i];
}
else
{
while (arr2[two] < 3 && two < j) two++;
arr2[two] = arr1[i];
}
}
}
return j+1;
} int getLDS(int n)
{
int j = 0, two = 0, thr = 0;
arr2[0] = arr1[0];
for (int i = 1; i < n; i++)
{
if (arr1[i] <= arr2[j]) arr2[++j] = arr1[i];
else
{
if (arr1[i] == 3)
{
while (arr2[thr] > 2 && thr < j) thr++;
arr2[thr] = arr1[i];
}
else
{
while (arr2[two] > 1 && two < j) two++;
arr2[two] = arr1[i];
}
}
}
return j+1;
} int main()
{
int n;
while (scanf("%d", &n) != EOF)
{
for (int i = 0; i < n; i++)
{
scanf("%d", &arr1[i]);
}
printf("%d\n", n-max(getLIS(n), getLDS(n)));
}
return 0;
}

POJ 3670 Eating Together 二分解法O(nlgn)和O(n)算法的更多相关文章

  1. POJ 3670 Eating Together (DP,LIS)

    题意:给定 n 个数,让你修改最少的数,使得它变成一个不下降或者不上升序列. 析:这个就是一个LIS,但是当时并没有看出来...只要求出最长LIS的长度,用总数减去就是答案. 代码如下: #inclu ...

  2. POJ 3670 Eating Together(LIS)

    Description The cows are so very silly about their dinner partners. They have organized themselves i ...

  3. poj 2456 Aggressive cows 二分 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=2456 解法 使用二分逐个尝试间隔距离 能否满足要求 检验是否满足要求的函数 使用的思想是贪心 第一个点放一头牛 后面大于等于尝试的距离才放 ...

  4. POJ 3273 Monthly Expense二分查找[最小化最大值问题]

    POJ 3273 Monthly Expense二分查找(最大值最小化问题) 题目:Monthly Expense Description Farmer John is an astounding a ...

  5. [POJ 2821]TN's Kindom III(任意长度循环卷积的Bluestein算法)

    [POJ 2821]TN's Kindom III(任意长度循环卷积的Bluestein算法) 题面 给出两个长度为\(n\)的序列\(B,C\),已知\(A\)和\(B\)的循环卷积为\(C\),求 ...

  6. poj 3258 River Hopscotch(二分+贪心)

    题目:http://poj.org/problem?id=3258 题意: 一条河长度为 L,河的起点(Start)和终点(End)分别有2块石头,S到E的距离就是L. 河中有n块石头,每块石头到S都 ...

  7. POJ 1064 Cable master (二分答案)

    题目链接:http://poj.org/problem?id=1064 有n条绳子,长度分别是Li.问你要是从中切出m条长度相同的绳子,问你这m条绳子每条最长是多少. 二分答案,尤其注意精度问题.我觉 ...

  8. POJ 3670 , 3671 LIS

    题意:两题意思差不多,都是给你一个序列,然后求最少需要改变多少个数字,使得成为一个最长不升,或者最长不降子序列. 当然3671是只能升序,所以更简单一点. 然后就没有什么了,用二分的方法求LIS即可. ...

  9. POJ 3273 Monthly Expense 二分枚举

    题目:http://poj.org/problem?id=3273 二分枚举,据说是经典题,看了题解才做的,暂时还没有完全理解.. #include <stdio.h> #include ...

随机推荐

  1. scala 学习笔记七 基于类型的模式匹配

    1.介绍 Scala 提供了强大的模式匹配机制,应用也非常广泛. 一个模式匹配包含了一系列备选项,每个都开始于关键字 case.每个备选项都包含了一个模式及一到多个表达式.箭头符号 => 隔开了 ...

  2. HDU 3535 AreYouBusy(混合背包)

    HDU3535 AreYouBusy(混合背包) http://acm.hdu.edu.cn/showproblem.php?pid=3535 题意: 给你n个工作集合,给你T的时间去做它们.给你m和 ...

  3. [mysql] C++操作mysql方法总结(1)

    From: http://www.cnblogs.com/magicsoar/p/3817518.html C++通过mysql的c api和通过mysql的Connector C++ 1.1.3操作 ...

  4. Mongo的安全验证

    参考如下的文档: https://docs.mongodb.org/manual/tutorial/enable-authentication/          1.1. 在启用匿名验证的情况下,创 ...

  5. Cass环境下光标无显示

    先安装CAD2004,十字光标正常显示:再安装CASS7.0,光标就不显示了.现在不清楚是CAD的问题,还是CASS的问题,多半是后者.重新配置了CASS环境也不行. 于是,打开CAD选项,显示,窗口 ...

  6. linux可视化桌面安装

    [root@VM_193_201_centos ~]# yum grouplist Loaded plugins: fastestmirror, langpacks There is no insta ...

  7. 利用Session完成用户的登录和注销

    用户的登录和注销是最常见的Web应用案例,当一个应用的客户登录了以后,其他所有的会话都得知道这个用户已经登录还很有可能得提取用户的昵称予以显示等等,所以,只有把登录成功的用户的信息放入到Session ...

  8. HTML解析模块

    import html html.escape(s, quote=True) 对特殊字符进行转义 Convert the characters &, < and > in stri ...

  9. java如何将毫秒数转为相应的年月日格式

    public static void main(String[] args) { Date date = new Date(); Long time = date.getTime(); System. ...

  10. java 获取昨天日期

    Calendar cal=Calendar.getInstance(); cal.add(Calendar.DATE,-1); Date d=cal.getTime(); SimpleDateForm ...