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.
Existem anéis cnt e o comprimento de cada anel é \ (l [i] \) .A resposta final é:
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;
}