BNU 4096 逆序 思维题

https://www.bnuoj.com/v3/problem_show.php?pid=4096

对于一个序列a,我们定义它的逆序数为满足a[i]>a[j]且i<j的有序对<i,j>的个数,这样的有序对称为逆序对。

例如 a[0]=1,a[1]=2,a[2]=4,a[3]=5,a[4]=3,存在的逆序对就有<2,4>和<3,4>,其逆序数就是2。

现在,给你一个长为N的序列,要求恰好执行K次交换操作,每次交换只能在相邻的两个数之间进行,问得到的结果序列其逆序数最小和最大可能是多少。

Input

输入数据有多组,每组数据包括两行,第一行有两个整数N (1<=N<=1,000)和K(0<=K<=1,000,000,000),分别是序列的长度和需要执行的交换操作的次数。

第二行有N个整数,依次给出了序列中的所有数,都在int范围内。

输入以EOF结束。

Output

对于每组数据,单独输出一行,包括两个整数,以一个空格隔开,第一个为执行恰好K次操作后得到的最小逆序值,第二个为最大逆序值。

Sample Input

5 1
1 2 3 4 5
5 1
1 2 3 5 4

Sample Output

1 1
0 2

Source

2009年北京师范大学新生程序设计竞赛正式赛

Author

Huang Kun @ BNU (modified from HUST campus)

这个关键在于想到

1、有重复数字

2、逆序对数目最大不一定是 n * (n - 1) / 2的,因为有重复数字的话,2、2、2这样的数据,就是0

我的思路是先求出一开始的逆序对数目,然后和k比较,因为它能移k次,按照最优的方案来说,每次都能增加/减去1个逆序对数目。

所以判断下当前有多少个逆序对now + k 和mx的关系即可

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
int n, k;
const int maxn = 1000 + 20;
int a[maxn];
int b[maxn];
map<int, int>book;
int calc(int a[]) {
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            if (a[i] > a[j]) ++ans;
        }
    }
    return ans;
}
bool cmp(int a, int b) {
    return a > b;
}
void work() {
    int bug = 0;
    book.clear();
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        b[i] = a[i];
        if (book[a[i]]) bug = 1;
        book[a[i]]++;
    }
    int now = calc(a);
    sort(a + 1, a + 1 + n, cmp);
    int mx = calc(a);
    int ansmi = 0;
    int ansmx = 0;
    int mxcut = 0, miadd = 0;
    if (n == 1) {
        printf("0 0\n");
        return;
    }
    if (now + k <= mx) {
        ansmx = now + k;
    } else {
        ansmx = mx;
        int left = now + k - mx;
        if (left % 2 == 1 && !bug) mxcut = 1;
    }
    if (now - k >= 0) {
        ansmi = now - k;
    } else {
        ansmi = 0;
        int left = k - now;
        if (left % 2 == 1 && !bug) miadd = 1;
    }
    printf("%d %d\n", ansmi + miadd, ansmx - mxcut);
}

int main() {
#ifdef local
    freopen("data.txt","r",stdin);
#endif
    while (scanf("%d%d", &n, &k) != EOF) work();
    return 0;
}

时间: 2024-08-07 08:38:41

BNU 4096 逆序 思维题的相关文章

算法题:一个N字节的数,如何逆序排列各个位(bit)?例如1字节的数 0010 0011 =&gt; 1100 0100

一个简简单单的题,如果用Java,C++,C估计还挺麻烦的,大体思路就是,开辟个N字节空间,用移位掩码方法逆向给每个bit赋值,这里由于N可能比较大,还得记录些额外的边界信息. 用Erlang则会简单很多: -module(bitoperator). -export([bit_reverse/1]). bit_reverse(Bin) -> L = [X || <<X:1>> <= Bin], Lr = lists:reverse(L), Br = list_to_bi

编程题:将数字0~5放入一个整型数组,并逆序输出数组

#include<stdio.h> void main() { int i,a[5]; for(i=0;i<5;i++)         /*给数组中元素赋值*/ a[i]=i; for(i=4;i>=0;i--)          /*逆序输出数组中元素值*/ printf("%3d",a[i]); printf("\n"); } 编程题:将数字0~5放入一个整型数组,并逆序输出数组,布布扣,bubuko.com

微软算法100题24 就地逆序单链表

第24 题:链表操作,单链表就地逆置 思路: 本来想拿两个指针分别指向当前节点和上一节点,在向后移动指针的过程中将当前节点的next指针逆向为上一节点,但这样就无法继续向后移动当前节点了.... 转换一下思路,对于n各节点,逆序的操作可以分解为把后面n-1个节点逆序,然后再把第一个节点放在已经逆序好的n-1个元素后面就可以了 -> f(n) = [f(n-1), 1] 最后还是回到了递归上... 其实递归是不是也可以归于divide&conquer范畴呢? 1 package com.rui

LeetCode开心刷题第四天——7逆序8字符转数字

7 Reverse Integer Given a 32-bit signed integer, reverse digits of an integer. Example 1: Input: 123 Output: 321 Example 2: Input: -123 Output: -321 Example 3: Input: 120 Output: 21 Note:Assume we are dealing with an environment which could only stor

python编程题-句子的逆序

对于一个字符串,请设计一个算法,只在字符串的单词间做逆序调整,也就是说,字符串由一些由空格分隔的部分组成,你需要将这些部分逆序. 给定一个原字符串A和他的长度,请返回逆序后的字符串. 测试样例: "dog loves pig",13 返回:"pig loves dog" python实现 class Reverse:     def reverseSentence(self, A, n):         # write code here         Alis

Python算法题----逆序列表

有这样一个列表[1, 2, 3, 4, 5, 6, 7, 8, 9]编程实现该列表逆序排列,将其变为[9, 8, 7, 6, 5, 4, 3, 2, 1] . 题目有了,看看怎么答,逆序排列,只需要将第一个和倒数第一个,第二个和倒数第二个,一直到中间那个位置的数字依次进行交换即可. 假设列表为data, 列表长度为len(data) [1, 2, 3, 4, 5, 6, 7, 8, 9] 0  1  2  3  4  5  6  7  8 从上图的列表和其下标可得出如下结论: 列表第1个元素下标

OJ刷题之《字符逆序》

Description 将一个字符串str的内容颠倒过来,并输出.str的长度不超过100个字符. Input 输入包括一行.第一行输入的字符串. Output 输出转换好的逆序字符串. Sample Input I am a student SampleOutput tneduts a ma I 代码如下: #include <iostream> #include <cstdio> using namespace std; int main() { int i=0; char s

C++刷题——2286: 逆序输出单词(串)

/* Copyright (c) 2014, 烟台大学计算机学院 * All rights reserved. * 文件名称:test.cpp * 作者:陈丹妮 * 完成日期:2015年 5 月 25 日 * 版 本 号:v1.0 */ Description 输入一个字符串,空格作为单词分隔符,统计其中的单词,并将单词逆序输出 Input 输入一个字符串 Output 逆序输出单词 Sample Input I love you! Sample Output you love I! #incl

算法题:链表的递归逆序

#include <iostream> using namespace std; struct Node { int data; Node *next; Node(int d = int()) :data(d), next(NULL){} }; class Clist { public: Clist(int a[], int n) :first(NULL) { int i = 0; Node *p = NULL; for (; i < n; i++) { Node *s = new No