题解 P4778【Counting swaps】
对 link 的抄写。
啊,还是不懂,以后再来看了。
problem
一次操作指随意选定 \(x,y\) 并交换 \(a_x,a_y\),请问有多少种方案,能用最少的操作次数重排一个排列 \(a\)?\(n\leq 10^5,P=10^9+7\)。
solution 0
连边 \(i\to a_i\),这是一张可以发起反攻的有向图,里面有很多个环,我们称这样的环为置换环。
引理一:对于一个 \(n\) 的置换环,完成对它的排序需要 \(n-1\) 次操作。
我们求出一个 \(f_i\) 表示大小为 \(i\) 的置换环排序的方案数,这是后文重点讨论内容,略之。
求出所有的置换环。因为环与环之间互不影响,相当于操作序列也互不影响,我们可以随意打乱环与环的相对顺序,这是多重集排列数(介绍见 ZROI371),记一个环的大小为 \(b_i\),则:
\[ans=\prod_i f_{b_i}\cdot \frac{\left(\sum_i(b_i-1)\right)!}{\prod_i (b_i-1)!}.
\]
到这里复杂度还是线性的。
solution 1
首先前人结论先摆出来:\(f_i=i^{i-2}\)。
求法一
一次交换后将大小为 \(n\) 的环分成大小分别为 \(i,n-i\) 的环,分别枚举:
- 两个操作序列交错插入,是多重集排列数
- 枚举交换哪一个数字
因此我们有:
\[f_1=1,f_n=\sum_{2i\leq n}\binom{n-2}{i-1}f_i f_{n-i}(2i==n?\frac{n}{2}:n).
\]
求法二
这样交换,每一次交换都连边,最终连出一棵树。然后不容易证明每棵树和每个合法操作方案一一对应。
所以答案为有标号无根树计数:\(n^{n-2}\)。
code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr,##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
const int P=1e9+9;
LL qpow(LL a,LL b,int p=P){LL r=1;for(a%=P;b;b>>=1,a=a*a%p) if(b&1) r=r*a%p; return r;}
template<int N,int P> struct C_prime{
LL fac[N+10],ifac[N+10];
C_prime(){
for(int i=fac[0]=ifac[0]=1;i<=N;i++) fac[i]=fac[i-1]*i%P;
ifac[N]=qpow(fac[N],P-2,P);
for(int i=N-1;i>=1;i--) ifac[i]=ifac[i+1]*(i+1)%P;
}
LL operator()(int n,int m){return fac[n]*ifac[n-m]%P*ifac[m];}
};
int n,a[100010],b[100010],cnt;
bool vis[100010];
LL ans=1,f[100010];
C_prime<100010,P> C;
int dfs(int x){
if(vis[x]) return 0;
vis[x]=1;
return dfs(a[x])+1;
}
int mian(){
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
if(vis[i]) continue;
int res=dfs(i);
if(res>1){
ans=ans*f[res]%P;
ans=ans*C.ifac[res-1]%P;
}
cnt++;
}
ans=ans*C.fac[n-cnt]%P;
printf("%lld\n",ans);
return 0;
}
void reset(){
memset(vis,0,sizeof vis);
cnt=0,ans=1;
}
int main(){
// #ifdef LOCAL
// freopen("input.in","r",stdin);
// #endif
f[1]=1;
for(int i=2;i<=1e5;i++) f[i]=qpow(i,i-2,P);
for(scanf("%*d");~scanf("%d",&n);reset(),mian());
return 0;
}
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/solution-P4778.html