题目来源:2016 CCPC 长春站
题意:
定义一个排列p1,p2,p3....pn的调和数值如下方公式。例如一个数列 1,2,3,4,5 的调和值就为4。
现在给出一个k,求出调和值第k小的一个permutation,这个permutation不唯一
思路:
首先可以先构造出来一个调和值为k的一对数,然后再让其他数前后调和值为1就ok了。
如果两个数gcd() = k , num1 = i * k , num2 = j * k ( i != j && i , j >= 1 ),那最小的两个数就为 k 和 2k 正好与题目中数据范围提示相对应
For each test case, there is only one line describing the given integers n and k (1≤2k≤n≤10000).
- 说明现在的思路是正确的,接下来的问题很重要,如何保证后面的排列中相邻两个数的gcd = 1呢?
只需要让序列为2k,k,k-1,k-2....1,k+1,k+2....2k-1, 2k+1,.....n即可,或者是2k,k,k-1,k-2....1,n,n-1...,2k+1,2k-1,.....,k+1 那能不能交换一下2k和k的位置?
不能,如果交换位置后序列为了保持后面排列中相邻两个数gcd = 1就得这样排序k,2k,2k-1,2k-2....k+1,k-1,...1,2k+1,2k+2....n,需要注意的是 k+1 和 k-1的gcd 不一定等于1例如k = 3 gcd(2,4) = 2/************************************************************************* > File Name: test3.cpp > Author: WArobot > Blog: http://www.cnblogs.com/WArobot/ > Created Time: 2017年04月17日 星期一 14时03分28秒 ************************************************************************/ #include<bits/stdc++.h> using namespace std; int n,k; void solve(){ printf(" %d %d",2*k,k); for(int i=k-1;i;i--) printf(" %d",i); for(int i=n;i>=k+1;i--){ if(i!=2*k) printf(" %d",i); } printf("\n"); } int main(){ int t , kase = 0; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&k); printf("Case #%d:",++kase); solve(); } return 0; }
刚开始不清楚permutation是不是唯一的,按逻辑来讲自然是不唯一,但是真正去做的时候却不敢去尝试了,总想一次性做对,太过理想化了。