交換のカウント

リンク

https://www.acwing.com/problem/content/description/214/

タイトル

1〜nの配置p1、p2、...、pnを指定すると、複数の操作を実行し、2つの整数x、yを毎回選択して、px、pyを交換できます。

p1、p2、...、pnを単調に増加する配列1、2、...、nに変更するには、少なくともm回の交換が必要であるとします。

m回の交換で上記の目標を達成できる操作方法の数を調べます。

結果は大きくなる可能性があるため、\(10 ^ 9 + 9 \)の係数後に値を出力するだけで済みます

たとえば、\(2,3,1 \)を配置するには、\(1,2,3 \)になるために少なくとも2つの交換が必要です。つまり、3つの操作方法があります。

方法1:最初に数値\(2,3 \)交換して\(3,2,1 \)にし、次に数値\(3,1 \)交換して\(1,2,3 \)にします。
方法2:最初の交換ディジタル\(2,1 \)(1,3,2 \)\、次に数字を交換\(3,2 \)(1,2,3 \)\
方法3:最初に数値\(3,1 \)交換して\(2,1,3 \)にし、次に数値\(2,1 \)交換して\(1,2,3 \)にします。
入力形式
最初の行には整数Tが含まれており、T組のテストケースがあることを示します。

各テストケースの前に空白行があります。

各テストケースには2行が含まれ、最初の行には整数nが含まれています。

2行目には、シーケンス\(p_1、p_2、...、p_n \)を表すn個の整数が含まれています

出力形式
各テストケースは結果を出力し、各結果は1行を占めます。

データ範囲
\(1≤n≤10^ 5 \)
入力サンプル:

3

3
2 3 1

4
2 1 4 3

2
1 2

出力例:

3
2
1

アイデア

\(a [j] = i \)数をiへの無向エッジに接続すると、\(cnt \)リングが生成され、最後に\(cnt \)リングがnポイントに分割されます。リング。

補題:最初に\(k \)ポイントを持つ単純なリング\(k \)自己ループに分割します。これには\(k-1 \)交換が必要です

リングの場合、2つのポイントを選択して2つの小さなリングに交換できます。
セット\(F [I]は、\)最小スイッチング周波数を表し、iは、リングの長さは、i番目の列からのプログラムの数に分割されています。
セットが\(T(x、y)は\)の長さを表す:(X + Y \)\ xの2つのループ長に分割され、Yは、プログラムループの数です。x + yメソッドがあると仮定すると、x = yの場合、メソッドの半分は対称的であることがわかります。ことを(X = Y \)\場合\(T(X、Y)= X \) または\(T(X、Y)
= X + Y \) X環およびY環相補的干渉を操作、我々は、Xリングのx-1ステップとyリングのy-1ステップの配置は、ダブルセットの完全な配置です。

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

cntリングがあり、各リングの長さは\(l [i] \)です。最終的な答えは次のとおりです。

\ [ans =(\ prod_ {i = 1} ^ {cnt} f [i])×\ frac {(nk)!} {\ prod_ {i = 1} ^ {cnt}(l [i] -1) !} \]

このステップを分析した後でも、複雑さは\(O(n ^ 2)\)のままです。
表を再生することで(いいえ、解、f [i] = \(i ^ {i-2} \)が高速なパワーでわかります:新しい時間の複雑さは\(O(nlogn)\)です

コード

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100010,mod=1e9+9;
int a[N],n,st[N],l[N],d;
int fac[N],f[N];
int qmi(int a,int b){
    int res=1;
    while(b){
        if(b&1) res=(LL)res*a%mod;
        a=(LL)a*a%mod;
        b>>=1;
    }
    return res;
}
void dfs(int u){
    d++;
    st[u]=1;
    if(!st[a[u]])  dfs(a[u]);
}
void init(){
    fac[0]=1;
    f[1]=1;
    fac[1]=1;
    for(int i=2;i<N;++i){
        f[i]=qmi(i,i-2);
        fac[i]=(LL)fac[i-1]*i%mod;
    }
}
int main(){
    int T;
    init();
    scanf("%d",&T);
    while(T--){
        memset(st,0,sizeof st);
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
        }
        int cnt=0;
        for(int i=1;i<=n;++i){
            if(!st[i]) {
                d=0;
                dfs(i);
                l[++cnt]=d;
            }
        }
        int ans=fac[n-cnt]%mod;
        for(int i=1;i<=cnt;++i){
            ans=(LL)ans*f[l[i]]%mod*(LL)qmi(fac[l[i]-1],mod-2)%mod;
        }

        cout<<ans<<endl;
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/jjl0229/p/12741769.html