ZOJ 2425-H - Inversion-给逆序对构造序列(构造)

http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=38458


给你一个n,m,表示原序列的长度和逆序对数,构造出字典序最小的原序列。



直接1到n排列;

当序列完全倒序,长度为i,其逆序对为  i乘(i-1)/2,

则我们把所有的 逆序对数列出来, 1  3  6  10  15.....


对于需要的逆序对m,我们找到大于m的第一个数,例如m=14,则我们找逆序对为15对应的i=5;


然后把原序列的最后5个倒序(字典最小)


得到 1 2 3 4 .......n n-1 n-2 n-3 n-4 n-5


然后此时我们看res= i乘(i-1)/2-m,得到多出来的逆序对,则例如res=3,我们只需要把后面逆序这段的第res(三)个数挪到最前面即可。

即 1 2 3 4 .......n n-1 n-2 n-3 n-4 n-5变成

1 2 3 4 .......n-2  n n-1 n-3 n-4 n-5  既符合个数,又是字典序最小


#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;

int ans[50000+5];
int num[50000+5];
void rever(int x,int y)
{
    if (x>y) return;
    int end=x+(y-x)/2;
    for (int i=x;i<=end;i++)
    {
        swap(ans[i],ans[y-i+x]);
    }
}
int main()
{
    int n;
        int m;
    while (scanf("%d%d",&n,&m)!=EOF && n!=-1&&m!=-1)
    {

    for (int i=1;i<=n ;i++)
        ans[i]=i;

            int flag=0;

        for (int i=1;i<=n;i++)
        if (i*(i-1)/2>=m){flag=i ;break;}


        rever(n-flag+1,n);

        int res=(flag*(flag-1)/2)-m;
        flag=n-flag+1;
        for (int i=1;i<=flag-1;i++)
            num[i]=ans[i];
        num[flag]=ans[flag+res];
        int j=flag;
        for (int i=flag+1;i<=n;i++)
        {
            if (j==flag+res) j++;
            num[i]=ans[j];
            j++;
        }
        for (int i=1;i<=n;i++)
        {
            if (i>1) printf(" ");
            printf("%d",num[i]);
        }
        printf("\n");


    }
    return 0;

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值