【简单数学】末日的传说
题目描述
只要是参加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的时候,世界末日就要降临。(瑟瑟发抖)。
什么是逆序:排在前面的那个比排在后面的那个更大,就是一个逆序。
这个题,需要一个一个数看,比如: 开始是 1,2,3,4,5,(样例)
那么当排成 5,4,3,2,1 逆序最多,有 (4+1)*4 /2 个,*用到公式(n-1)n /2(这里很好理解吧)
1…题目 要求出最小的那么排序。。
先看第一个数,1,如果 1在排在最后,那么最多就有 (4+1)* 4 /2 个逆序,这时候我们先放在一边,
看第二个数,2,(这时有数,2,3,4,5) 如果 2在最后,最多就有 (3+1)*3 /2 ==6个,6个大于
要求到达逆序数m=4(样例), 这样的情况就是说 不管你 1放在前面还是后面,我不需要1也能排出
逆序数m=4 的序列, 那么好极了,我们把1放在前面,(因为题目要排序最小)。。。
后面的推论都是一样,看当前数 的后一个数 ,它的最大逆序数是否大于m,如果大于,就放在前面,
2…如果小于呢? 如果小于,那就把数放在最后面,然后看有多少个逆序对,m减掉。(只看前面数对这一位数)
(比如2放在最后面,这时1放在最前, 在2前面比他大的有3,4,5,三个,那么逆序数为3,)
3… 我们开个数组来存放,前面都放数组前面,后面放数组后面,最后顺序输出数组就好了。
是不是太啰嗦了,,,,,,,还不是为了写清楚,(又啰嗦了哈。。。。。)
代码
#include<iostream>
using namespace std;
long long n,m;
int a[50005];
int main(){
cin>>n>>m;
int s=1,t=n;
for(int i=1;i<=n;i++){
long long maxi = (n-i)*(n-i-1) /2;
if(maxi >=m){
a[s] = i;
s++;
}else{
a[t] = i;
t--;
m -= n-i;
}
}
for(int i=1;i<=n-1;i++){
cout<<a[i]<<" ";
}
cout<<a[n]<<endl;
return 0;
}
转载:https://blog.csdn.net/A793488316/article/details/104666588