zoj2425
来源:互联网 发布:淘宝商家投诉买家 编辑:程序博客网 时间:2024/05/21 12:41
题目大意:
一个整数序列a1, a2, … , an的倒置数是数对(ai, aj)满足i < j并且ai > aj.给定n和倒置数m,你的任务是找到集合最小的序列{1,2,…,m},倒置数正好为m。
解题思路:
仔细观察下面的几组数据,每行分别表示invertion number和对应的一组最小的排列:
1: 2 1
2: 2 3 1
3: 3 2 1
4: 2 4 3 1
5: 3 4 2 1
6: 4 3 2 1
7: 2 5 4 3 1
8: 3 5 4 2 1
9: 4 5 3 2 1
10: 5 4 3 2 1
11: 2 6 5 4 3 1
12: 3 6 5 4 2 1
13: 4 6 5 3 2 1
14: 5 6 4 3 2 1
15: 6 5 4 3 2 1
相信很容易就看出了规律吧。首先,相同长度之间排列的规律,其次就是每组长度相同的数据中最后一个invertion number与长度的关系。哈哈,很简单吧。然后根据n,把前面的几个数从小到大输出来,然后将对应的invertion number的排列数的每个数加上前面已经输出的数的个数t,就是所求答案了。
当然了,记录这些排列显然内存是不够的,而且n的最大值为50000,是在太大,这时候,相同长度之间的规律就派上用场了。
我们只需要用一个数组list,以长度为下标,每组最后一个invertion number存起来,list[2]=1, list[3]=3,
list[4]=6, list[5]=10, list[6]=15, …时间复杂度O(n)
这样,给定m后,就可以通过二分查找,用O(logn)的时间找到对应的长度。然后根据所找到的规律,将结果打印出来,时间复杂度O(n)
这样,总的时间复杂度为O(n)。
代码如下:
#include<iostream>using namespace std;int n,m, id;int list[50001];int find(int num){ int L=1, R=n, mid; while(L<R-1) { mid=L+R>>1; if(list[mid]>= num) R=mid; else L=mid; } return L;}int main(){ for(int i=1; i<50000; ++i) list[i+1]=list[i] + i; while(1) { cin>>n>>m; if(n==-1 && m==-1) break; if(m==0) { cout<<1; for(int i=2; i<=n; ++i) cout<<' '<<i; cout<<endl; } else { id=find(m); int end=n-id; int num; for(int i=1; i<end; ++i) cout<<i<<' '; num=m-list[id]; cout<<(num+end); for(int i=id; i>=0 ;--i) if(num!=i) cout<<' '<<(i+end); cout<<endl; } } return 0;}
- ZOJ2425
- zoj2425
- 17 - 03 - 26 图解HTTP(30)
- linux下裁剪可执行文件
- MySQL入门之C语言操作MySQL
- 单例设计模式
- JAVA异常处理
- zoj2425
- High "Resmgr:Cpu Quantum" Wait Events In 11g Even When Resource Manager Is Disabled (文档 ID 949033.1)
- 数据结构实验之链表七:单链表中重复元素的删除
- 洛谷 1739_表达式括号匹配_模拟
- DDL数据定义语言
- 关于电脑定时关机等DOS指令
- python学习笔记(27)--类的详解8(基于类的状态机)
- Picasso封装优化
- 微服务架构