poj2299 二分思想

poj2299   http://poj.org/problem?id=2299
题意: 
一个含有n个数的数组, 每次只能交换相邻的两个数, 求最少操作多少次可以使该数组变成一个有序数组(从小到大)。 
分析: 
先说一下归并排序吧。 二分的思想, 就是将一元素集合分割成两个或更多个子集合,对每一个子集合分别排序,然后将排好序的子集合归并为一个集合。看图理解会好一点! 

归并排序核心操作:将一维数组中前后相邻的两个有序序列归并为一个有序序列。

那看一下我们这题, 其实就是在归并排序的过程中顺便计算一下移动次数, 就好了。 举个例子:例如图中前半部分数组{8,3,2,9}, 先分为两部分{8,3} 和{2,9} 。 {8,3}又分为{8} 和{3}, 8又在3前面所以合并8,3需要移动一次 sum= 1, {2,9}分为{2} he {9}, 本来就是有序的所以合并2,9不需要移动 sum= 1; 接下来这一步就该合并{3,8} 和{2,9}了。 2前面有两个比它大的数,所以要交换两次, 2才能排到第一位 sum = sum+2 = 3; 9比前面的都大就不用交换啦 sum= 3。

#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;

const int N = 500005;
__int64 sum, a[N], c[N];
int n;
void merge1(int low, int high, int mid)
{
    int i = low, j = mid + 1;
    int k = 0;
    while((i <=  mid) && (j <= high))
    {
        if(a[i] <= a[j])
        {
            c[++k] = a[i];
            i++;
        }
        else if(a[i] > a[j])
        {
            c[++k] = a[j];
            j++;
            sum += (mid - i + 1);
        }
    }
    while(i <= mid)
        c[++k] = a[i++];
    while(j <= high)
        c[++k] = a[j++];
    if(low < high)
    {
        for(int i = high; i >= low; i--)
        {
            a[i] = c[k];
            k--;
        }
    }
}
//通过ac()不断将数组划分为更小的区间,再通过merge1()将划分的数组再合并回来, 并且合并的时候使其变得有序
void ac(int low, int high)
{
    if(low < high)
    {
        int mid = (low + high) / 2;
        ac(low, mid);
        ac(mid + 1, high);
        merge1(low, high, mid);
    }
}
int main()
{
    while(scanf("%d", &n) != EOF && n)
    {
        for(int i = 1; i <= n; i++)
            scanf("%I64d", &a[i]);
        sum = 0;
        ac(1, n);
        printf("%I64d\n", sum);
    }
    return 0;
}

时间: 2024-10-14 07:30:35

poj2299 二分思想的相关文章

数据结构与算法学习之路:LIS——最长递增序列的动态规划算法和二分思想算法

一.最长递增序列的问题描述: 求一个整数序列的最长递增子序列,子序列不要求是连续的.例如: Input:4,6,9,6,7,6,3,8,10:Output:5 二.解决方法: 1.用动态规划的方法解决.从问题我们可以知道,我们最终得到的最长递增子序列,其任意一段子序列也是对应序列中的最长子序列.这样说可能不好理解,就以上面的例子来说: 最长子序列为:4,6, 7, 8, 10.在这段子序列的子序列里选一个,例如:4,6,7.则4,6,7也是4,6,9,6,7,6,3这段序列的最长子序列. 对于动

poj 3111 K Best 最大化平均值 二分思想

poj 3111 K Best 最大化平均值 二分思想 题目链接: http://poj.org/problem?id=3111 思路: 挑战程序竞赛书上讲的很好,下面的解释也基本来源于此书 设定条件C(x):=可以选择使得单位重量的价值不小于x 如何判定C(x)是否可行 假设选了某个物品的集合是S,那么单位重量的价值是:\[ \sum\limits_{i \in S} {v_i } /\sum\limits_{i \in S} {w_i } \] 因此就变成了判断是否存在S满足下面的条件:\[

对二分思想的理解及结对编程

一.对二分法思想的体会 1.二分法是运用分治策略的典型例子,也称折半查找,充分利用了元素间的次序关系,是一种效率较高的查找方法.实现二分算法有递归和非递归两种方式. 2.基本思想:将n个元素分成大致相同的两半,取a[n/2]与x作比较.如果x=a[n/2],则找到x,算法终止:如果a<[n/2],则只在数组a的左半部分继续搜索x:如果x>a[n/2],则只在数组的右半部分继续搜索x. 3.代码实现: int BinarySearch(Type a[],const Type&x,int

背包/母函数?/二分思想?

1033: 空运物资 时间限制: 1 Sec  内存限制: 128 MB提交: 8  解决: 4[提交][状态][讨论版][Edit] [TestData] 题目描述 在灾区,多数人已经受伤,缺水,少食物,精神处在崩溃的边缘.很多人的生存条件仅能维持几天.灾民需要帐篷.衣物.食品和医疗器材.药品等物资.14日上午,中央军委委员.空军司令员许其亮组织召开空军首长办公会,将空军下一步救灾重点确定为抢救伤员.空投.空运.空军各部队都派出多架运输机,准备向灾区空运急需物品.现在已知四种打包过的急需物品重

二分思想

#include<cstdio> using namespace std; //二分查找 int bsrch(int l,int r,int k,int a[]) { int mid; while(l<=r){ mid=(l+r)/2; if(a[mid]>k)r=mid-1; else if(a[mid]==k)return mid; else l=mid+1; } return -1; } //有序区间下界//第一个大于等于k的元素的位置 int lowerBound(int

The Sum of 0 for four numbers(拆解加二分思想)

个人心得:单纯用二分法一直超时,后面发现我的那种方法并没有节省多少时间,后面看了大神的代码,真的是巧妙, 俩个数组分别装a+b,c+d.双指针一个指向最后,从第一个开始想加,加到刚好大于0停止,再看是否存在和为0的情况. 很巧妙,因为此时i,j所指想加刚好大于0,因为是排完序的,所以i往后面走的时候,大于j的数相加一定大于0,所以卡的非常好: 就没有再指针跳转回去了,佩服! The SUM problem can be formulated as follows: given four list

算法与数据结构总结1 二分查找与旋转排序数组

一. 二分搜索(Binary Search)模板及其理解 1.通用模板,解决start, end, mid, <(<=), >(>=)等问题 http://www.lintcode.com/en/problem/binary-search/ class Solution { public: /** * @param nums: The integer array. * @param target: Target number to find. * @return: The firs

二分查找如何“花式”卖萌

二分查找,敢说这货埋在土里化到灰里应该都是认得的.其原理思想也是如此的简单明了,敲代码时都懒得经过反射弧.但事实上,据Knuth神犇描述,第一个木有bug的二分查找是这个算法发表之后12年在出现,但后来发现还是存在一些数组越界的小问题.而如今,我们大都是开门见山的学习被前辈们优化证明的算法,这也是“牛逼顿”所谓的站在巨人的肩膀上,却也如此. 回头来看二分查找如何“花式”卖萌. Problem:给定一个有序数组A,且数组中的元素存在重复,各大一个目标值target,求目标值在数组的的下标的区间(即

POJ2109 高精度(含大数开方)+二分

1 高精度(含大数开方)+二分 一个技巧和三点注意: 技巧:假设k^n=p;(k的n次方),那么p的位数/n得到的是k的位数!例如:n=7,p=4357186184021382204544,p的位数为22,用22/7的结果向上取整,得到4,即为k的位数,也就是说k的取值范围是1000~9999.(引自code_pang)不利用这一点,高精度+直接二分,也会超时.用这一个技巧合理缩小二分的范围. 注意:看code的main中的注释. (二分思想不熟练,因为二分算法很高效,所以一定要暴力点直接确定l