Luogu-1338-末日传说

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

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

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

1, 2, 3, … N

第二天,日历自动变为

1, 2, 3, … N, N-1

……每次它都生成一个以前未出现过的“最小”的排列——把它转为N+1进制后数的数值最小。

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

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

题目链接

Luogu-1338-末日传说

输入输出格式

输入格式

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

输出格式

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

输入输出样例

输入样例1:

5 4

输出样例1:

1 3 5 4 2

说明

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

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

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

所有数据均有解。

题解

题目意思看了半天没看懂搜了题解看到的题意。意思是给你一个N,让你在1-N的序列中找到一个序列使得这个序列的逆序对的个数满足M,并且该序列的字典序最小。

对于一个序列,它的最大逆序对的个数给n*(n-1)/2,即该序列严格降序。所以当我们按位来考虑这个序列的逆序数时,我们去判断这一位对该序列逆序对的贡献是否比M大。例如N = 5,M = 4.我们在考虑1的时候可以计算得出,剩下的4位数可以产生的最大逆序对的个数是比M大的,所以这个1可有可无,我们就可以把他放到序列的最前端。而到了2时我们发现,去掉了这个2是无法满足逆序对大于M的要求,此时按照贪心我们把2放到最后,这样可以使2这个数产生的逆序对最多,也就使M减小的最多,进而影响后面我们可以找到跟多的无关元素。这样就好写了。对于每个数都有两种方式

去掉当前数,剩下的数仍可构成比M多个逆序对
把当前数放到后方,让M-(当前数提供的逆序对的个数)
这样直接O(n)的时间复杂度就过去了(要开long long)。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <bits/stdc++.h>
typedef long long ll;
const int MAXN = 1e5+7;
const int INF = 0x7fffffff;
using namespace std;
ll a[MAXN];

int main() {
ll n,m;
cin >> n >> m;
ll ans[MAXN],l = 1,r = n;
for(ll i = 1; i <= n; i++) {
ll t = (n-i)*(n-i-1)/2;
if(t >= m) {
ans[l] = i;
l++;
} else {
ans[r] = i;
r--;
m -= (r - l + 1);
}
}
for(ll i = 1; i <= n; i++)
cout << ans[i] << " ";
return 0;
}

Powered by Hexo and Hexo-theme-hiker

Copyright © 2018 - 2020 Never Give Up! All Rights Reserved.

访客数 : | 访问量 :