Counting swaps
Posted a1b3c7d9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Counting swaps相关的知识,希望对你有一定的参考价值。
给你一个1~n的排列,问用最少的交换次数使之变为递增排列的方案数\(mod\ 10^9+7\),1?≤?n?≤?10^5。
解
显然最少的交换次数不定,还得需要找到最小交换次数,而考虑到交换为复杂的过程,考虑状态的性质,所以不难想到画出,+为箭头指向方向
_ _
| + | +
2 1 4 3
+ | + |
|_| |_|
于是你会发现实际上我们的变换为递增序列,即把所有的环都变成自环,而交换两个数字即拆环,所以不难知道,一个环拆掉的最少的次数为环的大小-1(因为你对一个环进行一次交换操作,就变成了两个环,以此类推,拆成n个环,要操作n-1次)。
有了这样一个想法,于是考虑环的组合计数问题的方法,可以以拆环为状态划分来设递推方程,于是设\(f[i]\)表示长度为i的环的变成全部是自环的最少操作次数的方案数,拆成两个环又有不同的拆分方式,于是设\(T[i][j]\)表示拆成两个长i,j的环的方案数,于是我们有
\[T[i][j]=i==j?i+j>>1:i+j\]
\[f[i]=\sum_{j=1}^{[i/2]}f[j]\times f[i-j]\times T[j][i-j]\times\frac{(i-1)!}{(j-1)!(i-j)!}\]
于是,设初始序列为长\(l_1,l_2...,l_m\)的环构成的,易知
\[ans=(n-m)!\prod_{i=1}^mf[l_i]\frac{1}{(l_i-1)!}\]
但是对于f找规律,我们发现\(f[i]=i^{i-2}\),于是我们可以利用矩阵快速幂,时间复杂度应为\(O(nlog(n))\)。
参考代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
#define ll long long
#define yyb 1000000009
#define lsy 1000000007
#define _ putchar('\n')
using namespace std;
int num[100001];
bool check[100001];
ll dp[100001],jc[100001],jv[100001];
il ll pow(ll,ll);
il void prepare();
template<class free>void pen(free);
template<class free>il void read(free&);
int main(){
int cjx,i,j,n,len,tot;ll ans;
prepare(),read(cjx);
while(cjx--){
read(n),memset(check,0,sizeof(check));
for(i=1;i<=n;++i)read(num[i]);tot&=0,ans=1;
for(i=1;i<=n;++i)
if(!check[i]){
j=i,++tot,len&=0;
do j=num[j],++len,check[j]|=true;
while(i!=j);
ans=ans*dp[len]%yyb*jv[len-1]%yyb;
}ans=ans*jc[n-tot]%yyb,pen(ans),_;
}
return 0;
}
template<class free>
void pen(free x){
if(x>9)pen(x/10);putchar(x%10+48);
}
il ll pow(ll x,ll y){
ll ans(1);
while(y){
if(y&1)ans=ans*x%yyb;
x=x*x%yyb,y>>=1;
}return ans;
}
void prepare(){
ri int i,j;jc[1]=jc[0]=jv[1]=jv[0]=dp[1]=1;
for(i=2;i<=100000;++i)
jc[i]=jc[i-1]*i%yyb,jv[i]=
pow(jc[i],lsy),dp[i]=pow(i,i-2);
}
template<class free>
il void read(free& x){
x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}
以上是关于Counting swaps的主要内容,如果未能解决你的问题,请参考以下文章
关于将 string::swap() 与临时对象一起使用的问题