末日的传说 洛谷p1338

news/2024/12/12 5:27:07/

题目描述

只要是参加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。

所有数据均有解。


解法一:暴力(20分)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=50005;
int n,m,a[MAXN],b[MAXN],tmp[MAXN],num;
inline void merge(int l,int m,int r)
{int i=l,j=m+1,k=l;while(i<=m&&j<=r){if(b[i]<=b[j]) tmp[k++]=b[i++];else{num+=m-i+1;tmp[k++]=b[j++];}}while(i<=m)tmp[k++]=b[i++];while(j<=r)tmp[k++]=b[j++];for(i=l;i<=r;i++)b[i]=tmp[i];
}
inline void mergesort(int l,int r)
{if(l>=r) return;int m=l+r>>1;mergesort(l,m);mergesort(m+1,r);merge(l,m,r);
}
int main()
{ios::sync_with_stdio(false);int i,j,tot=0;cin>>n>>m;f(i,1,n){a[i]=i;}do{num=0;memcpy(b,a,sizeof(int)*(n+1));mergesort(1,n);if(num==m) break;}while(next_permutation(a+1,a+1+n));f(i,1,n){cout<<a[i]<<' ';}return 0;
}

解法二:(100)

我们考虑把这个问题缩小范围。

比如n=5,在决定了最小的数“1”的位置之后,剩下的几个数是2 3 4 5,但是他们

具体是多少没必要关心,我们只要关心他们的相对大小关系

所以考虑完当前最小的数,算出这个数对答案的贡献,然后减掉这个贡献,

就可以转而解决一个更小的子问题。(即n-->n-1)

回到题目上,要求是求一个有m个逆序对的字典序最小的排列。

我们知道一个长度为n的排列最多有(n-1)*n/2个逆序对,也知道一个排列的逆序对数越多,排列字典序越大。

所以如果当前m不比当前的(n-2)*(n-1)/2(也就是减少一个数之后的最多的逆序对数)大,

就可以直接把当前的最小数放在最前面,这肯定是最优的。

反之,则考虑最小数的放置位置。

假设当前排列长为n,最小数为a,则a有n种放法,放在从左到右第i个位置时会生成i-1个逆序对

(因为它左边有i-1个比他大)。

因为m大于n-1长度排列最多所能产生的逆序数,所以a不可能放在最前面,否则不满足条件。

怎么办呢?想到之前说的逆序对越多字典序越大,我们就必须让剩下的数能构成的逆序对数尽量小,所以a要放到最后,这样m减少的最多。

放完了a,问题就变成了n-1和m-(a的贡献)的子问题,递归求解即可。时间复杂度O(n)。

#include<iostream>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=50005;
int n,m,a[MAXN];
int main()
{ios::sync_with_stdio(false);int i,j,head,tail;cin>>n>>m;head=1;tail=n;f(i,1,n){int Max_num=1LL*(n-i)*(n-i-1)/2;if(m<=Max_num){a[head++]=i;}else{a[tail--]=i;m-=tail-head+1;}}f(i,1,n){cout<<a[i]<<' ';}return 0;
}



http://www.ppmy.cn/news/927071.html

相关文章

昔日“东方神童”逝世,4岁读完初中课程,17岁中科院硕博连读,网友:湖南华容的传说...

杨净 发自 凹非寺量子位 报道 | 公众号 QbitAI 他4岁读完初中&#xff0c;我4岁刚不尿裤子。 他8岁进入重点高中&#xff0c;我8岁刚学加减法。 他13岁考入大学&#xff0c;我13岁还和同学打架。 他17岁硕博连读&#xff0c;我17岁忙着早恋。 …… 最近&#xff0c;天涯论坛上一…

luogu P1338 末日的传说

https://www.luogu.org/problem/P1338 题目描述 只要是参加jsoi活动的同学一定都听说过Hanoi塔的传说&#xff1a;三根柱子上的金片每天被移动一次&#xff0c;当所有的金片都被移完之后&#xff0c;世界末日也就随之降临了。 在古老东方的幻想乡&#xff0c;人们都采用一种…

P1338 末日的传说

题目描述: 只要是参加jsoi活动的同学一定都听说过Hanoi塔的传说&#xff1a;三根柱子上的金片每天被移动一次&#xff0c;当所有的金片都被移完之后&#xff0c;世界末日也就随之降临了。 在古老东方的幻想乡&#xff0c;人们都采用一种奇特的方式记录日期&#xff1a;他们用…

udx实现揭秘之---------udx的慢启动带宽探测

我们都知道bew wnd*1000/rtt 当慢启动的时候&#xff0c;每收一个ack,可以这样调整发送速度当前sendspeed sendspeed mss/rtt.并且更新wnd->wnd1. udx的变形版本是sendspeed checksize/rtt; 但是这种增加速度太快&#xff0c;在到达临界点的时候&#xff0c;很容易击…

【东方传说】世间万物 六界轮回

昨天写了“轮回”不想在宁波网通的帖子上看到了“六界轮回” 一时间不知道说什么好。先贴在这里吧。&#xff08;昨天写的其实不好&#xff0c;有点词不达意。大概是从小缺乏练习吧&#xff09; 六界 从洛神踏湖、观音水瓶&#xff0c; 到雷峰塔压白娘子&#xff0c;狐媚轻扣…

末日传说

Description 只要是参加jsoi活动的同学一定都听说过Hanoi塔的传说&#xff1a;三根柱子上的金片每天被移动一次&#xff0c;当所有的金片都被移完之后&#xff0c;世界末日也就随之降临了。 在古老东方的幻想乡&#xff0c;人们都采用一种奇特的方式记录日期&#xff1a;他们用…

1263 末日传说

末日传说 Time Limit(Common/Java):1000MS/3000MS Memory Limit:65536KByte Description 只要是参加JSOI活动的同学一定都听说过汉诺塔的传说&#xff1a;三根柱子上的金片每天被移动一次&#xff0c;当所有的金片都被移完后&#xff0c;世界末日也就随之降临了。 在古老东方的…

HCIP第十一天(笔记)

BGP的选路原则 前提条件 --- 丢弃所以不可用的路由信息 1.优选preferred-vlaue属性值最大的路由 2.优选local_preference 3.本地始发的BGP路由优于从其他对等体学习到的路由&#xff0c;本地 始发的路由优先级&#xff1a;优选手动聚合>自动聚合>network>import>从…