zoukankan      html  css  js  c++  java
  • 洛谷 P1338 末日的传说

    题目链接:https://www.luogu.org/problemnew/show/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。

    所有数据均有解。

    题目意思很好理解,就是叫你求逆序数为m且字典序最小的数字排列。我们可以暴力模拟但是n太大暴力肯定会超时,只能另想办法。

    打表发现最优解一定是先升序在降序,而且我们知到对于1到n的逆序数最多为n*(n-1)/2。

    因为所有数据均有解,从1到n遍历,对于数字i,如果(n-i)*(n-i-1)/2>=m就将i放到左边,否则将i放到右边并令m=m-未存放数字的区间大小。

    #include<iostream>
    using namespace std;
    #define ll long long
    ll n,m,ans[100005];
    int main()
    {
        cin>>n>>m;
        int l=1,r=n;
        for(int i=1;i<=n;i++)
        {
            if((n-i)*(n-i-1)/2>=m)
            ans[l++]=i;
            else
            {
                ans[r--]=i;
                m-=r-l+1;
            }
        }
        for(int i=1;i<=n;i++)
        {
            cout<<ans[i];
            if(i!=n)cout<<" ";
            else cout<<endl;
        }
        return 0;
    }
  • 相关阅读:
    观察者模式的结构
    策略模式
    EJB 配置多个数据源
    EJB3 调用的存储过程
    Android学习笔记_49_Android中自定义属性(attrs.xml,TypedArray的使用)
    Android学习笔记_48_若水新闻客户端源码剖析
    博客样式
    oracle 基础知识(四)常用函数
    oracle 基础知识(三)
    oracle 基础语法(二)
  • 原文地址:https://www.cnblogs.com/chen99/p/10575480.html
Copyright © 2011-2022 走看看