zoukankan      html  css  js  c++  java
  • P1338 末日的传说 逆序数对

    题目描述

    只要是参加jsoi活动的同学一定都听说过Hanoi塔的传说:三根柱子上的金片每天被移动一次,当所有的金片都被移完之后,世界末日也就随之降临了。

    在古老东方的幻想乡,人们都采用一种奇特的方式记录日期:他们用一些特殊的符号来表示从1开始的连续整数,1表示最小而N表示最大。创世纪的第一天,日历就被赋予了生命,它自动地开始计数,就像排列不断地增加。

    我们用1-N来表示日历的元素,第一天日历就是  1, 2, 3, … N

    第二天,日历自动变为 1, 2, 3, … N, N-1……每次它都生成一个以前未出现过的“最小”的排列——把它转为N+1进制后数的数值最小。

    日子一天一天地过着。有一天,一位预言者出现了——他预言道,当这个日历到达某个上帝安排的时刻,这个世界就会崩溃……他还预言到,假如某一个日期的逆序达到一个值M的时候,世界末日就要降临。

    什么是逆序?日历中的两个不同符号,假如排在前面的那个比排在后面的那个更大,就是一个逆序,一个日期的逆序总数达到M后,末日就要降临,人们都期待一个贤者,能够预见那一天,到底将在什么时候到来?

    格式

    输入格式:

    只包含一行两个正整数,分别为N和M。

    输出格式:

    输出一行,为世界末日的日期,每个数字之间用一个空格隔开。

    样例

    输入样例#1: 复制
    5 4
    
    输出样例#1: 复制
    1 3 5 4 2
    

    说明

    对于10%的数据有N <= 10。

    对于40%的数据有N <= 1000。

    对于100%的数据有 N <= 50000。

    所有数据均有解。

    思路:我们知道,逆序对的个数,在最大情况下,是n*(n-1)/2。

    所以枚举位置1—n,计算i放在当前位置时,后面能产生的最多逆序对是多少,如果能超过m,就把i放在当前位置。

    如果不能,说明这个数太小了,需要放在后面增加逆序对个数,把它扔到未确定区间的最后一个。

    同时,因为把一个小数放到了后面,接下来未确定区间中不管有多少逆序对,其中的每一个数,都会与这个数产生一对逆序对,所以我们需要减小m,减小的长度就是区间长度。

    代码:

     1 #include"bits/stdc++.h"
     2 #define ll long long
     3 #define cl(x) scanf("%lld",&x)
     4 #define pl(x) printf("%lld
    ",x)
     5 using namespace std;
     6 const int N = 1e6 + 5;
     7 ll n,m;
     8 int a[N];
     9 int main() {
    10     cl(n),cl(m);
    11     ll l=1,r=n;
    12     for(int i=1;i<=n;i++){
    13         ll tmp=(n-i)*(n-i-1)/2;
    14         if(tmp>=m) a[l++]=i;
    15         else a[r--]=i,m-=r-l+1;
    16     }
    17     for(int i=1;i<=n;i++) printf("%d%c",a[i],i==n?'
    ':' ');
    18 
    19     return 0;
    20 }
  • 相关阅读:
    outlook 2007无法连接exchange server时的解决方法
    Source模式和Design模式无法转换 在VS2008
    自定义CreateUserWizard 控件
    自定义CreateUserWizard 控件
    锋利的jQuery第三章
    Repeater控件的ItemDataBound事件
    jquery获取select,option所有的value和text
    Jquery中的缩写总结
    asp.net本质论学习笔记第二章
    jquery的append函数
  • 原文地址:https://www.cnblogs.com/mj-liylho/p/9393526.html
Copyright © 2011-2022 走看看