AcWing212 计数交换

这个式子就不再推导了,书上写的很明确,但感觉解释的不是很明白,别的博客都是直接抄的原文,于是写一下自己的理解。

f[i]=\sum_{x+y=i} f[x]*f[y]*T(x,y)*\frac{(i-2)!}{(x-1)!(y-1)!}

解释下这个式子

1、为什么不同x,y之间可以直接相加。

第一步的交换是把大环 i 拆成 x,y 两个小环,不同的 x,y 第一步当然不同。那么无论后面怎么排,第一步不同,相互之间肯定无重复。

2、为什么可以直接 *T(x,y) 。

同样的x,y,环里的数不同,那么在拆 i 的时候第一步一定不同,同上。

3、为什么有多重集。

对于拆成的两个环,自己需要多少步形成自环x,y之间是没有关系的,所以是乘法原理。

这个时候有个问题,直接乘是先x再y的数量,对于x,y两个环交叉进行的数量并没有统计在内,对于每一种x的方案,y的方案,交叉进行的时候,我们不改变所有x环交换的相对顺序,比如 假设x有3步,X1,X2,X3,我们在x环和y环组合一起的序列中,不改变X1,X2,X3的相对位置,X1还在X2前面,但有可能X1和X2之间插入了Y1。

这样的话,就构成了一个多重集。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#define ms(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef double ab;
const int N=1e5+5;
const ll mod=1e9+9;
ll jc[N],jc_inv[N],f[N];
int n;
int a[N],vis[N];
vector<int> ans;
void exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x=1;
        y=0;
        return ;
    }
    exgcd(b,a%b,y,x);
    y-=(a/b)*x;
}
ll qpow(ll a, ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1)
            res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return res;
}
void init()
{
    f[1]=jc[0]=jc_inv[0]=jc[1]=jc_inv[1]=1;
    for(int i=2;i<=N-5;i++)
    {
        f[i]=qpow(i,i-2);
        jc[i]=jc[i-1]*i%mod;
        ll x,y;
        exgcd(jc[i],mod,x,y);
        jc_inv[i]=(x%mod+mod)%mod;
    }
}
int main()
{
    int T;
    init();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        ll ans=1;
        int l=0;
        for(int i=1,len=1;i<=n;i++,len=1)
        {
            if(vis[i]) continue;
            vis[i]=1;
            for(int j=a[i];!vis[j];j=a[j])
            {
                vis[j]=1;
                ++len;
            }
            ans=ans*f[len]%mod;
            ans=ans*jc_inv[len-1]%mod;
            ++l;
        }
        ans=ans*jc[n-l]%mod;
        printf("%lld\n",ans);
        for(int i=1;i<=n;i++)
            vis[i]=0; 
    }
}

猜你喜欢

转载自blog.csdn.net/Luowaterbi/article/details/104175367
212