• P4778 Counting Swaps 题解


    第一道 A 掉的严格意义上的组合计数题,特来纪念一发。
    第一次真正接触到这种类型的题,给人感觉好像思维得很发散才行……


    对于一个排列 (p_1,p_2,dots,p_n),对于每个 (i)(p_i) 连一条边,可以发现整个构成了一个由若干环组成的图,目标是将这些环变为自环。
    引理:把长度为 (n) 的环变为 (n) 个自环,最少交换次数为 (n-1)
    用归纳法证,对于当前情况,任意一次交换都将其拆为两个环,由淘汰赛法则可知引理成立。
    (F_n) 表示在最少交换次数下把长度为 (n) 的环变为 (n) 个自环,有多少种交换方式。由前所述,我们每次都将其拆为两个环,不妨设两个环长度为 (x,y),并记 (T(x,y)) 表示有多少种方法可将一个长度为 (n) 的环变为长度为 (x,y) 的两个环,那么当 (n) 为偶数且 (x=y) 时有 (T(x,y)=frac{n}{2}),其他情况 (T(x,y)=n)。由于 (x) 环与 (y) 环的操作互不干扰,两边的操作可以随意排列,因此这里就是一个多重集的全排列。
    于是有了递归表达式: $$F_n=sum_{x+y=n}left(T(x,y)F_xF_yfrac{(n-2)!}{(x-1)!(y-1)!} ight)$$ 对于题目中的所有 (k) 个环,记它们的长度为 ({l_k}),最终答案为:

    [prod^{k}_{i=1}F_{l_{i}}dfrac{(n-k)!}{prod^{k}_{i=1}(l_i-1)!} ]

    还没完,经过JOJO的洗礼之后发现 (F_n=n^{n-2})!复杂度立马降为 (O(nlog n))……
    (找环这个骚操作是照题解区 dalao 学的,只能 orz

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=1e5+5;
    const ll mod=1e9+9;
    int n,a[N],L[N],cnt;
    ll fac[N]={1,1},F[N]={0,1};
    bool vis[N];
    
    ll qpow(ll bas,ll p)
    {
        ll res=1; bas%=mod;
        for(;p;p>>=1)
        {
            if(p&1) res=res*bas%mod;
            bas=bas*bas%mod;
        }
        return res;
    }
    
    int dfs(int x)
    {
        vis[x]=1;
        if(vis[a[x]]) return 1;
        return dfs(a[x])+1;
    }
    
    int main()
    {
        int T; scanf("%d",&T);
        for(int i=2;i<N;++i)
            fac[i]=i*fac[i-1]%mod,
            F[i]=qpow(i,i-2)%mod;
        while(T--)
        {
            memset(vis,0,sizeof(vis));
            cnt=0;
            scanf("%d",&n);
            for(int i=1;i<=n;++i)
                scanf("%d",&a[i]);
            for(int i=1;i<=n;++i)
                if(!vis[i]) L[++cnt]=dfs(i);
            ll ans=fac[n-cnt];
            for(int i=1;i<=cnt;++i)
                ans=ans*F[L[i]]%mod*qpow(fac[L[i]-1],mod-2)%mod;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    多线程中,上锁的理解
    sql server 2008 联机丛书
    序列化是线程安全的么
    对象化下的编程——字段
    Dic实现工厂模式
    design principle:java 回调与委派/委托机制(转)
    风筝数据结构学习笔记(2)后序遍历二叉树(非递归)
    风筝数据结构学习笔记(1)利用链式存储结构和递归构建二叉树
    吕震宇老师《设计模式系列》
    吕震宇老师《设计模式随笔系列》
  • 原文地址:https://www.cnblogs.com/wzzyr24/p/12234527.html
Copyright © 2020-2023  润新知