P1338 末日的传说 (逆序对)

题目链接

题面:

在这里插入图片描述

题解:

如何让逆序对数为m的序列字典序最小呢? 假设位置p是最后一个原始序列的位置,那这个点应该尽量靠右,才能使得字典序最小。而为了保证有m个逆序对,要求p后面的逆序对数尽量大。需要降序排列。

这样问题就转成找点p,同时在找到p时还需要知道 m-后面所有逆序对数剩余的值,这个值要在点p身上修改。

则我们现在可以直接输出序列。 1)p之前的部分按照顺序输出 2)输出p,如果后面逆序对不够,则需要修改p点再输出。 3)逆序输出p之后的部分,注意如果p之前改点了,需要多判断一下。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<deque>
#define ll long long
#define llu unsigned ll
#define ld long double
#define iu unsigned int
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e16;
const double pi=acos(-1.0);
const int mod=1e9+7;
const int maxn=10100;
int main(void)
{
    int n,m;
    scanf("%d%d",&n,&m);
    //形成这些逆序对一共用了多少个数
    int cnt=0;

    //当前这一位最多能增加多少个逆序对
    int pm=1;

    //改动的第一位(转折点)需要增加多少个逆序对
    int minn=0;
    while(m)
    {
        minn=min(m,pm);
        m-=minn;
        pm++;
        cnt++;
    }
    //一共需要cnt+1位来形成这m个逆序对
    cnt=n-cnt;
    //令cnt=n-cnt
    //那么cnt-1位是不需要动的
    for(int i=1;i<cnt;i++)
        printf("%d ",i);
    //转折点为cnt+minn,那么他后面有cnt,cnt+1,。。。,cnt+minn-1共minn个数比它小
    //形成minn个逆序对
    printf("%d ",cnt+minn);

    //剩下的都是降序排列,形成尽量多的逆序对
    for(int i=n;i>=cnt;i--)
        if(i!=cnt+minn)
            printf("%d ",i);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值