递推置换,交换次数最少得到升序序列
题意:
给定一个1~n的排序,可以通过一系列的交换变成1,2,…,n, 给定n和k,统计有多少个排列至少需要交换k次才能变成有序的序列。
题解:
每个长度为n循环需要交换n-1次才能将交换到对应的位置,例如1->2,2->4,4->1,(1,2,4)位置上对应值为(2,4,1) 相当于一个长度为3的环逆时针旋转了1格,要变换回来,需要跟原位置交换,因为成环,所以共n-1次 那么对于序列P,有x个循环节,长度为n,就需要交换n-x次 对于f[i][j],表示交换j次能变为1~i的序列的种数 我们找到递推式:f[i][j]=f[i-1][j]+f[i-1][j-1]*(i-1),边界是f[1][0]=1,其余为0 解释:新增的i,如果与自己构成循环,那么循环数和长度都加一,交换数不变,所以是f[i-1][j] 新增的i,如果参加到其他环中,每个数后一种,共i-1种,循环数不变,长度加一,所以是f[i-1][j-1]*(i-1) 例如1->2,2->3,3->1,{2,3,1};将4添加到1后就是1->4,4->2,2->3,3->1,序列为{4,3,1,2};其他同上
1 #include<bits/stdc++.h> 2 #define mp make_pair 3 #define pb push_back 4 #define first fi 5 #define second se 6 #define pw(x) (1ll << (x)) 7 #define sz(x) ((int)(x).size()) 8 #define all(x) (x).begin(),(x).end() 9 #define rep(i,l,r) for(int i=(l);i<(r);i++) 10 #define per(i,r,l) for(int i=(r);i>=(l);i--) 11 #define FOR(i,l,r) for(int i=(l);i<=(r);i++) 12 #define eps 1e-9 13 #define PIE acos(-1) 14 #define cl(a,b) memset(a,b,sizeof(a)) 15 #define fastio ios::sync_with_stdio(false);cin.tie(0); 16 #define lson l , mid , ls 17 #define rson mid + 1 , r , rs 18 #define ls (rt<<1) 19 #define rs (ls|1) 20 #define INF 0x3f3f3f3f 21 #define LINF 0x3f3f3f3f3f3f3f3f 22 #define freopen freopen("in.txt","r",stdin); 23 #define cfin ifstream cin("in.txt"); 24 #define lowbit(x) (x&(-x)) 25 #define sqr(a) a*a 26 #define ll long long 27 #define ull unsigned long long 28 #define vi vector<int> 29 #define pii pair<int, int> 30 #define dd(x) cout << #x << " = " << (x) << ", " 31 #define de(x) cout << #x << " = " << (x) << "\n" 32 #define endl "\n" 33 using namespace std; 34 //********************************** 35 ull dp[25][25];//dp[i][j]表示前i个数至少用k次交换的排列数 36 int n,k; 37 //********************************** 38 void Init() 39 { 40 FOR(i,1,21){ 41 dp[i][0]=1; 42 rep(j,1,i){ 43 dp[i][j]=dp[i-1][j-1]*(i-1)+dp[i-1][j];; 44 } 45 } 46 } 47 //********************************** 48 int main() 49 50 { 51 Init(); 52 while(cin>>n>>k,n+k){ 53 cout<<dp[n][k]<<endl; 54 } 55 return 0; 56 }