ZOJ 3574 Under Attack II 归并排序求逆序对

Under Attack II


Time Limit: 5 Seconds     
Memory Limit: 65536 KB



Because of the sucessfully calculation in Under Attack I, Doctor is awarded with Courage Cross and promoted to lieutenant. But the war seems to end in never, now Doctor has a new order to help anti-aircraft troops calculate the proper number of supply sites
needed for SAMs in battle regions.

According to intel, enemy bombers go straight across battle region and the bombing runs are continous. So their routes divides the region into several parts. The missles SAM needed are provided by supply sites. Because it‘s dangerous to cross fireline, Ufo
suggests that every part of battle regions divided by firelines should have a supply site so that the SAMs can safely get enough ammo.

Now that the task is clear, Doctor is asked to calculate how many supply sites are at least needed. The bombers‘ routes are lines
y=kx+b given in format as k,b, of course k b are same to their ordinary meanings. Assume the battle region is a rectangle with infinity height, the left x-cooridinate and right x-cooridinate are given so that the width
of rectangle is fixed.

Input

The input consists of multiple cases.

The first line are the left x-cooridinate a and right x-cooridinate
b
of battle region. a b are both in the range of [0,1000]. Of course
a will not exceed b.

Next lines will describe enemy bombing routes number n.n can be up to 30000.

Following n lines are k and b of each bombing route.k
b are in range of [-100000,100000].

It‘s guaranteed that no three lines (including the two battle region bound lines) will go through one point.

Output

Output the least number of supply sites needed.

Sample Input

1 2
1
1 5

Sample Output

2

Hint

In sample, line y=x+5 divides the region between x=1 and x=2 into two parts, so the outcome is 2.

题意:告诉x轴上的一个区间范围,告诉n条直线,以及每条直线的k,b值,问这些直线能把XA 到 XB 这个区间分成多少个平面区间,任意三条直线保证不会交于一个点。

思路:对于区间内任意两条直线,如果不相交,那么就是分成三个区域,如果交点在范围内就是分成4个区域,如果交点在边界上,那么就是三个区域。多画几个图就会发现,范围内分的区域数,实际上等于直线数加交点数加一,那么现在关键就是求交点数,先把左边交点按照从小到大排序,相等时右边交点也从小到大排,交点的个数,就是逆序对数,那么可以用归并排序来求右边范围的逆序对数是多少。

#include <iostream>
#include <stdio.h>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

struct Node
{
    int a,b;
}f[30009];

int cmp(Node a,Node b)
{
    if(a.a==b.a)
        return a.b<b.b;
    return a.a<b.a;
}

int tmp[30009];
int num;

void mergefun(int le,int mid,int ri)
{
    int p=le,q=mid+1,i=1;
    while(p<=mid && q<=ri )
    {
        if(f[p].b>f[q].b)
            {tmp[i++]=f[q++].b;num+=(mid-p+1);}
            else
            tmp[i++]=f[p++].b;
    }
    while(p<=mid) tmp[i++]=f[p++].b;
    while(q<=ri) tmp[i++]=f[q++].b;

    int j=1;
    for(i=le;i<=ri;i++,j++)
        f[i].b=tmp[j];
}

void mergesort(int le,int ri)
{
    if(le==ri) return;
    int mid=(le+ri)/2;

    mergesort(le,mid);
    mergesort(mid+1,ri);

    mergefun(le,mid,ri);
}

int main()
{
    int xa,xb;
    int k,b;
    int n;

    while(~scanf("%d%d",&xa,&xb))
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&k,&b);
            f[i].a=(k*xa+b);
            f[i].b=(k*xb+b);
        }
        sort(f+1,f+n+1,cmp);
        num=0;
        mergesort(1,n);

        printf("%d\n",num+n+1);

    }

    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-20 20:25:34

ZOJ 3574 Under Attack II 归并排序求逆序对的相关文章

利用归并排序求逆序对

1.归并排序 先回顾一下归并排序 归并排序中归和并的意义: 归:递归.递归的将输入数组进行分割至长度为1. 并:合并.将各长度为1的数组顺序合并,完成归并排序. 归并排序的整体思想为分治,主体算法为: public void mergeSort(int[]arr, intbegin, intend) { if (begin != end) { int mid = (begin + end) /2; mergeSort(arr,begin, mid); mergeSort(arr,mid + 1,

归并排序求逆序对

归并排序求逆序对 by mps [1]什么是逆序对? 对于一个数列需要按从小到大排序,如果有ai,aj且满足ai>aj和i<j则ai,aj为一组逆序对 [2]如何求逆序对? 我们发现,我们可以暴力枚举i,j,然后逐一判断并累加答案即可,时间复杂度O(N2)        但是对于数据量大一点的题目,只有不断地TLE了→_→ [3]归并排序求逆序对 逆序对的定义(见[1])是一组本应该有序的序列中的逆序对,那么我们就想到了排序,但由于是要22匹配,我们又想到了归并排序 归并排序大致内容如下: 将

ZJNU 1247 归并排序求逆序对

逆序对——高级 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 118   Accepted: 28 Description 对于一个包含N个非负整数的数组A[1..n],如果有i < j,且A[ i ]>A[ j ],则称(A[ i] ,A[ j] )为数组A中的一个逆序对.  例如,数组(3,1,4,5,2)的逆序对有(3,1),(3,2),(4,2),(5,2),共4个. 求n个数中的逆序对个数. Input 第一

2014 HDU多校弟五场A题 【归并排序求逆序对】

这题是2Y,第一次WA贡献给了没有long long 的答案QAQ 题意不难理解,解题方法不难. 先用归并排序求出原串中逆序对的个数然后拿来减去k即可,如果答案小于0,则取0 学习了归并排序求逆序对的方法,可以拿来当模板 TVT 贴代码了: 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostream&g

【BZOJ4769】超级贞鱼 归并排序求逆序对

[BZOJ4769]超级贞鱼 Description 马达加斯加贞鱼是一种神奇的双脚贞鱼,它们把自己的智慧写在脚上——每只贞鱼的左脚和右脚上各有一个数.有一天,K只贞鱼兴致来潮,排成一列,从左到右第i只贞鱼会在右脚写Ai,左脚上写上i:第二年,这K只贞鱼以右脚的数为第一关键字.左脚的数为第二关键字,从小到大排成一列.然后,它们决定重编号,从左到右第i只贞鱼会在右脚上写上左脚的数,在左脚上写i:第三年,它们按第二年的方法重排列.重编号......N年后,对于从左到右第i和第j贞鱼,若i<j且第i只

【归并排序求逆序对】

[AC] 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 const int maxn=1e5+2; 6 int a[maxn]; 7 int tmp[maxn]; 8 int n; 9 ll ans; 10 void Merge(int l,int m,int r) 11 { 12 int i=l,j=m+1; 13 int k=l; 14 while(i<=m&&

归并排序求逆序对 //(洛谷)U4566 赛车比赛

https://www.luogu.org/problem/show?pid=U4566 显然的逆序对,以前只是嘴巴ac,这次终于打了出来. 逆序对其实就是冒泡排序的排序次数....但是一般的排序时间复杂度为O(n^2),于是都会想到归并排序... 一.二路归并 已知两个有序数组,将其归并为一个有序数组 很显然,将首元素比较,小的扔进目的数组,最后把剩下的扔进去.. 1 int a[n],b[m],tmp[n+m]; 2 int i=1,j=1,k=1; 3 while(i<=n&&

归并排序求逆序对模板(未完待续)

归并排序求逆序对题目(持续更新) \(1.\) \(Ultra\) \(Quicksort\) (需要该篇博文的阅读密码) 归并排序求逆序对 细节:传参三个,左.中.右三端点,每次运算注意中端点总取左右端点和的一半:返回条件为左右端点相等,此时无需排序. \(View\) \(Code\) void msort(int l,int mid,int r) { if(l==r) return; msort(l,(l+mid)>>1,mid); msort(mid+1,(r+mid+1)>&g

poj2299(归并排序求逆序对)

题目链接:https://vjudge.net/problem/POJ-2299 题意:给定一个序列,每次只能交换邻近的两个元素,问要交换多少次才能使序列按升序排列. 思路:本质就是求逆序对.我们用归并排序求逆序对,这也是简单的cdq分治. #include<cstdio> #include<algorithm> #include<cstdlib> #include<cmath> using namespace std; typedef long long