zoukankan      html  css  js  c++  java
  • 《算法竞赛进阶指南》0x36组合计数 计数交换

    题目链接:https://www.acwing.com/problem/content/214/

    给出一个排列打乱之后的顺序,要求将其还原成升序全排列的方法数,通过计算,将一个长度为n的环变成自环需要用n-1步,将一个长度为n的环变成自环可能的步数有n^(n-2)种,假设这个给出的全排列中环的数量是k,那么一共需要n-k步。由于每次步数的选择中,每一类的是没有顺序的,所以需要利用多重集的公式进行去重。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<string.h>
    using namespace std;
    const int maxn = 100010;
    const int mod = 1000000009;
    typedef long long ll;
    ll jc[maxn];
    int n;
    int a[maxn],p[maxn];
    bool vis[maxn];
    ll power(ll a,ll b){
        ll ans=1;
        b%=mod;
        while(b){
            if(b&1)
                ans=(ans*a)%mod;
            a=(a*a)%mod;
            b>>=1;
        }
        return ans;
    }
    int main(){
        jc[0]=1;
        for(int i=1;i<=maxn-1;i++)jc[i]=(jc[i-1]*i)%mod;
        int T;
        cin>>T;
        while(T--){
            cin>>n;
            int cnt=0;
            ll ans=1;
            memset(vis,0,sizeof(vis));
            for(int i=1;i<=n;i++)scanf("%d",&a[i]);
            for(int i=1;i<=n;i++)p[i]=a[i];
            for(int i=1;i<=n;i++){
                if(vis[i])continue;
                int len=1;    
                vis[i]=1;
                for(int j=p[i];j!=i;j=p[j])vis[j]=1,len++;
                cnt++;
                ans=(ans*(len==1?1:power(len,len-2)))%mod;
                ans=(ans*power(jc[len-1],mod-2))%mod;//求解逆元 
            }
            ans=(ans*jc[n-cnt])%mod;
            cout<<ans<<endl;
        }    
        return 0;
    }
  • 相关阅读:
    Attributes in C#
    asp.net C# 时间格式大全
    UVA 10518 How Many Calls?
    UVA 10303 How Many Trees?
    UVA 991 Safe Salutations
    UVA 10862 Connect the Cable Wires
    UVA 10417 Gift Exchanging
    UVA 10229 Modular Fibonacci
    UVA 10079 Pizza Cutting
    UVA 10334 Ray Through Glasses
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13279808.html
Copyright © 2011-2022 走看看