Codeforces Round #309 (Div. 2) -D. Kyoya and Permutation

Kyoya and Permutation

这题想了好久才写出来,没看题解写出来的感觉真的好爽啊!!!

题目大意:题意我看了好久才懂,就是给你一个序列,比如[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 }
View Code
原文地址:https://www.cnblogs.com/CJLHY/p/7551542.html