这题想了好久才写出来,没看题解写出来的感觉真的好爽啊!!!
题目大意:题意我看了好久才懂,就是给你一个序列,比如[4, 1, 6, 2, 5, 3],第一个数字
的值是4,那么我们找下标为4的数( 跟链表差不多意思 ),然后一直找到底,这些数分为一类,
如[4, 1, 6, 2, 5, 3] 就可以分为三类,[4, 2, 1] , [6, 3],[5],这三类,然后每个类里面按从大
往小排,然后类之间按字典序排,[4, 1, 6, 2, 5, 3] 重新组合之后为,[4, 2, 1] [5] [6, 3]=[4, 2, 1, 5, 6, 3]
我们把进行重组之后数字序列保持不变的 序列 按字典序大小从小到大排出来。
然后给你一个长度n和数字k,让你找出长度为n的序列中排第k个的序列是什么。
思路:首先我想的是怎样的序列它重新组合之后还是原序列,我打了一下表,基础序列为
1,2,3,4,……,n,只有相邻的两个数交换之后得到的是满足要求的序列。如果我们从小到大
枚举出所有的序列显然是不可能的复杂度太高,那么我们先求总共的序列数,我们设dp[ i ],
表示从i 到 n 一共有多少种交换方法。dp[n]=1,那么状态转移方程为dp[ i ] = dp[ i + 1 ]+dp[ i + 2 ] ,
为什么呢,因为到i这里的时候,我们可以选择交换i 和 i+1 或者不交换,交换的话种数是dp[ i +2 ],
不交换的话是dp[ i + 1 ]。
我们从n开始往前找,找到第一个大于k的dp[ s ],那么s和s+1是必须要交换的,因为如果不交换
种数为dp[ s + 2 ],又dp[ s + 2] < k 不满足。这样我们的问题就变成了k为k-dp[ s + 2]的相同问题
我们可以用dfs递归求解。
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 ll dp[60],n,k,ans[60],cnt[60]; 5 void dfs(ll k) 6 { 7 if(k==1) return; 8 int item=-1; 9 for(int i=n;i>=1;i--) 10 { 11 if(dp[i]>=k) 12 { 13 item=i; 14 break; 15 } 16 } 17 swap(ans[item],ans[item+1]); 18 dfs(k-dp[item+1]); 19 } 20 int main() 21 { 22 cin>>n>>k; 23 dp[n]=1; dp[n-1]=2; 24 for(int i=n-2;i>=1;i--) dp[i]=dp[i+1]+dp[i+2]; 25 for(int i=1;i<=n;i++) ans[i]=i; 26 dfs(k); 27 printf("%d",ans[1]); 28 for(int i=2;i<=n;i++) printf(" %d",ans[i]); 29 puts(""); 30 return 0; 31 }