本题就是一题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. C/C++语言中变量作用域:局部变量,全局变量,文件级变量

    C/C++语言中的变量分为全局变量和局部变量. 这样的划分方式的根据是变量的可见范围或者叫做作用域. 1 局部变量 局部变量指的是定义在{}中的变量,其作用域也在这个范围内.尽管常见的局部变量都是定义 ...

  2. windows下安装redis 以及phpredis的扩展 (windows redis php&php7)

    一.工具准备 1. redis for windows 下载 https://github.com/MSOpenTech/redis 2. PHP扩展下载 http://pecl.php.net/pa ...

  3. Android指令处理流程源代码追踪

    1.拨号界面输入*#06#.显示IMEI号,这是怎么出来的? 2.怎样高速的找出Android平台中的指令? 1. 在DialpadFragment中的EditText注冊一个Textchanged的 ...

  4. ArcGIS Pro体验03——主界面

    主界面和Office类似,应该上手比较快.新建Map后,加载了美国地图,毕竟是ESRI公司嘛.除项目(PROJECT),另外还有六个菜单面板,分别是地图(MAP).插入(INSERT).分析(ANAL ...

  5. Field.setAccessible()方法

    http://blog.csdn.net/kjfcpua/article/details/8496911 java代码中,常常将一个类的成员变量置为private 在类的外面获取此类的私有成员变量的v ...

  6. MySQL主从常见的架构

    Master-Slave  级联  双Master互为主备

  7. cordova 强制竖屏

    orentation的默认值是default 可使用的值有:default, landscape (横屏), portait (竖屏) orentation可以将设备锁定方向,不受设备旋转影响. 方案 ...

  8. Android Studio 1.0RC1版公布

    Android Studio 1.0RC1 版本号公布. 下面是官网该版本号说明: Android Studio 1.0 Release Candidate 1 November 20th, 2014 ...

  9. 用javascript的isNan()函数,可以判断是否为数字

    var getstockid = $.trim($("#SearchString").val()); if (!isNaN(getstockid)) alert('是数字!'); ...

  10. Qt音乐播放器制作(一)Easy Player

    前几天忽然间认为,事到现在Qt的功底也有些基础了,为什么不试着自己做个玩意来玩玩呢?刚好在开源中国逛代码区的时候看到一个QKugou的项目,就想着做一个在线音乐播放器好了. 于是開始着手准备,忙活了一 ...