Contando troca

Link

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

Título

Dado um arranjo 1 ~ n p1, p2, ..., pn, você pode executar várias operações, selecionar dois números inteiros x, y de cada vez, trocar px, py.

Suponha que a alteração de p1, p2, ..., pn em um arranjo monotonicamente crescente 1,2, ..., n exija pelo menos m trocas.

Descubra quantos métodos de operação podem atingir a meta acima com apenas m trocas.

Como o resultado pode ser grande, você só precisa gerar o valor após o módulo \ (10 ​​^ 9 + 9 \) .

Por exemplo, organizar \ (2,3,1 \) requer pelo menos 2 trocas para se tornar \ (1,2,3 \) . Existem três métodos operacionais, a saber:

Método 1: Primeiro troque o número \ (2,3 \) para se tornar \ (3,2,1 \) , depois troque o número \ (3,1 \) para se tornar \ (1,2,3 \) .
Método 2: Primeiro troque o número \ (2,1 \) para se tornar \ (1,3,2 \) , depois troque o número \ (3,2 \) para se tornar \ (1,2,3 \) .
Método 3: Primeiro troque o número \ (3,1 \) para se tornar \ (2,1,3 \) , depois troque o número \ (2,1 \) para se tornar \ (1,2,3 \) .
Formato de entrada A
primeira linha contém o número inteiro T, indicando que existem T conjuntos de casos de teste.

Haverá uma linha em branco antes de cada caso de teste.

Cada caso de teste contém duas linhas, a primeira linha contém o número inteiro n.

A segunda linha contém n números inteiros, representando a sequência \ (p_1, p_2, ..., p_n \) .

Formato de saída
Cada caso de teste gera um resultado e cada resultado ocupa uma linha.

Intervalo de dados
\ (1≤n≤10 ^ 5 \)
Amostra de entrada:

3

3
2 3 1

4
2 1 4 3

2
1 2

Saída de amostra:

3
2
1

Idéias

A idéia é conectar o número \ (a [j] = i \) a uma borda não direcionada para i, o que gerará anéis \ (cnt \) e, finalmente, dividiremos os anéis \ (cnt \) em n Ring.

Lema: Primeiro, divida um anel simples com \ (k \) pontos em \ (k \) auto-loops, o que requer trocas \ (k-1 \)

Para um anel, podemos escolher dois pontos para trocar em dois pequenos anéis.
Vamos \ (f [i] \) denotar o número de soluções que dividem o anel de comprimento i em auto-strings com o número mínimo de trocas.
Seja \ (T (x, y) \) denotar o número de soluções para dividir um anel de comprimento: \ (x + y \) em dois anéis de comprimento x, y. Supondo que existem métodos x + y, pode-se descobrir que quando x = y, metade dos métodos é simétrica. Isso \ (x = y \) quando \ (T (x, y) = x \) , ou \ (T (x, y)
= x + y \) operando complementar interferência x e y anel de anel, que x O arranjo do passo x-1 no anel e o passo y-1 no anel y é um arranjo completo de um conjunto duplo.

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

Existem anéis cnt e o comprimento de cada anel é \ (l [i] \) .A resposta final é:

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

Mesmo depois de analisar esta etapa, a complexidade ainda é \ (O (n ^ 2) \) .
Ao jogar na mesa (não, a solução, podemos ver que f [i] = \ (i ^ {i-2} \) , através do poder rápido : A nova complexidade de tempo é \ (O (nlogn) \)

Código

#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;
}

Acho que você gosta

Origin www.cnblogs.com/jjl0229/p/12741769.html
Recomendado
Clasificación