3602 Counting Swaps 0x30「数学知识」例题

背景

https://ipsc.ksp.sk/2016/real/problems/c.html

Just like yesterday (in problem U of the practice session), Bob is busy, so Alice keeps on playing some single-player games and puzzles. In her newest puzzle she has a permutation of numbers from 1 to n. The goal of the puzzle is to sort the permutation using the smallest possible number of swaps.

Instead of simply solving the puzzle, Alice is wondering about the probability of winning it just by playing at random. In order to answer this question, she needs to know the number of optimal solutions to her puzzle.

描述

给定一个 1~n 的排列 p_1,p_2,…,p_n,可进行若干次操作,每次选择两个整数 x,y,交换 p_x,p_y。设把 p_1,p_2,…,p_n 变成单调递增的排列 1,2,…,n 至少需要 m 次交换。求有多少种操作方法可以只用 m 次交换达到上述目标。因为结果可能很大,你只需要输出对 10^9+9 取模之后的值。1≤n≤10^5。
例如排列 2,3,1 至少需要2次交换才能变为 1,2,3。操作方法共有3种,分别是:
先交换数字2,3,变成 3,2,1,再交换数字3,1,变成 1,2,3。
先交换数字2,1,变成 1,3,2,再交换数字3,2,变成 1,2,3。
先交换数字3,1,变成 2,1,3,再交换数字2,1,变成 1,2,3。

You are given a permutation p1, …, pn of the numbers 1 through n. In each step you can choose two numbers x < y and swap px with py.

Let m be the minimum number of such swaps needed to sort the given permutation. Compute the number of different sequences of exactly m swaps that sort the given permutation. Since this number may be large, compute it modulo 109 + 9.

输入格式

The first line of the input file contains an integer t specifying the number of test cases. Each test case is preceded by a blank line.

Each test case consists of two lines. The first line contains the integer n. The second line contains the sequence p1, …, pn: a permutation of 1, …, n.

In the easy subproblem C1, 1 ≤ n ≤ 10.

In the hard subproblem C2, 1 ≤ n ≤ 105.

输出格式

For each test case, output a single line with a single integer: x xmod(109+9)" id="MathJax-Element-1-Frame" role="presentation" style="display: inline; line-height: normal; text-align: left; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border: 0px; padding: 0px; margin: 0px; position: relative;" tabindex="0">mod(10^9+9), where x is the number of ways to sort the given sequence using as few swaps as possible.

样例输入

3

3
2 3 1 4
2 1 4 3 2
1 2

样例输出

3
2
1

样例解释

In the first test case, we can sort the permutation in two swaps. We can make the first swap arbitrarily; for each of them, there’s exactly one optimal second swap. For example, one of the three shortest solutions is “swap p1 with p2 and then swap p1 with p3”.

In the second test case, the optimal solution involves swapping p1 with p2 and swapping p3 with p4. We can do these two swaps in either order.

The third sequence is already sorted. The optimal number of swaps is 0, and thus the only optimal solution is an empty sequence of swaps.

        </article>

分析

参照Rose_max的题解。

对于每个位置i,我们向他应该填的数所在的位置p[i]连一条边

如此会出来一些环,我们的目的是将这些环拆成n个自环

对于一个长度为n的环,我们发现要把他拆成n个自环至少需要n-1次操作

设T(x,y)表示将长度为n的环拆成长度分别为x,y的环的方案数,设f[n]表示将长度为n的环拆成n个自环的方案数

画图可知

T(x,y)=n/2" role="presentation" style="position: relative;">T(x,y)=n/2 n为偶数且x=y

T(x,y)=n" role="presentation" style="position: relative;">T(x,y)=n otherwise

对于长度为x的环的操作全部看成0,长度为y的环的操作全部看成1,进行多重集的排列。可以发现这对应出的就是长度为n的环要拆成n个自环的操作方案

根据多重集的排列公式有

f[n]=∑x+y=nT(x,y)∗f[x]∗f[y]∗(n−2)!(x−1)!(y−1)!" role="presentation" style="text-align: center; position: relative;">f[n]=∑x+y=nT(x,y)∗f[x]∗f[y]∗(n−2)!(x−1)!(y−1)!

最终答案也可以用一个多重集的排列给出

对于k个长度分别为l1,l2,...,lk" role="presentation" style="position: relative;">l1,l2,...,lk的环,有

ans=∏f[l1]∗f[l2]∗...∗f[lk]∗(n−k)!(l1−1)!(l2−1)!...(lk−1)!" role="presentation" style="text-align: center; position: relative;">ans=∏f[l1]∗f[l2]∗...∗f[lk]∗(n−k)!(l1−1)!(l2−1)!...(lk−1)!

递推复杂度O(n2)" role="presentation" style="position: relative;">O(n2)

我们把f的前几项求出来找规律可以发现f[n]=nn−2" role="presentation" style="position: relative;">f[n]=nn−2

如此复杂度降为O(nlog⁡n)" role="presentation" style="position: relative;">O(nlogn)

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;
rg char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x){
return x=read<T>();
}
typedef long long ll; co int SIZE=1e5+1,mod=1e9+9;
int p[SIZE],v[SIZE],T,n;
ll jc[SIZE];
int power(int a,int b){
int c=1;
for(;b;b>>=1){
if(b&1) c=(ll)c*a%mod;
a=(ll)a*a%mod;
}
return c;
}
int main()
{
// freopen(".in","r",stdin),freopen(".out","w",stdout);
jc[0]=1;
for(int i=1;i<=1e5;++i) jc[i]=jc[i-1]*i%mod;
read(T);
while(T--){
read(n);
for(int i=1;i<=n;++i) read(p[i]),v[i]=0;
int cnt=0;
ll ans=1;
for(int i=1;i<=n;++i){
if(v[i]) continue;
int len=1;
v[i]=1;
for(int j=p[i];j!=i;j=p[j]) v[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;
printf("%lld\n",ans);
}
return 0;
}

CH3602 Counting Swaps的更多相关文章

  1. Counting swaps

    Counting swaps 给你一个1-n的排列,问用最少的交换次数使之变为递增排列的方案数\(mod\ 10^9+7\),1 ≤ n ≤ 10^5. 解 显然最少的交换次数不定,还得需要找到最小交 ...

  2. 洛谷P4778 Counting swaps 数论

    正解:数论 解题报告: 传送门! 首先考虑最终的状态是固定的,所以可以知道初始状态的每个数要去哪个地方,就可以考虑给每个数$a$连一条边,指向一个数$b$,表示$a$最后要移至$b$所在的位置 显然每 ...

  3. luogu P4778 Counting swaps

    计数套路题?但是我连套路都不会,,, 拿到这道题我一脸蒙彼,,,感谢@poorpool 大佬的博客的指点 先将第\(i\)位上的数字\(p_i\)向\(i\)连无向边,然后构成了一个有若干环组成的无向 ...

  4. LFYZOJ 104 Counting Swaps

    题解 #include <iostream> #include <cstdio> #include <algorithm> #include <cmath&g ...

  5. lfyzoj104 Counting Swaps

    问题描述 给定你一个 \(1 \sim n\) 的排列 \(\{p_i\}\),可进行若干次操作,每次选择两个整数 \(x,y\),交换 \(p_x,p_y\). 请你告诉穰子,用最少的操作次数将给定 ...

  6. luoguP4778 Counting swaps

    题目链接 题解 首先,对于每个\(i\)向\(a[i]\)连边. 这样会连出许多独立的环. 可以证明,交换操作不会跨越环. 每个环内的点到最终状态最少交换步数是 \(环的大小-1\) 那么设\(f[i ...

  7. P4778 Counting Swaps 题解

    第一道 A 掉的严格意义上的组合计数题,特来纪念一发. 第一次真正接触到这种类型的题,给人感觉好像思维得很发散才行-- 对于一个排列 \(p_1,p_2,\dots,p_n\),对于每个 \(i\) ...

  8. 0x36 组合计数

    组合计算的性质: C(n,m)= m! / (n!(m-n)!) C(n,m)=C(m-n,m); C(n,m)=C(n,m-1)+C(n-1,m-1); 二项式定理:(a+b)^n=sigema(k ...

  9. 萌新笔记——Cardinality Estimation算法学习(二)(Linear Counting算法、最大似然估计(MLE))

    在上篇,我了解了基数的基本概念,现在进入Linear Counting算法的学习. 理解颇浅,还请大神指点! http://blog.codinglabs.org/articles/algorithm ...

随机推荐

  1. 雷林鹏分享:C# 泛型(Generic)

    C# 泛型(Generic) 泛型(Generic) 允许您延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候.换句话说,泛型允许您编写一个可以与任何数据类型一起工作的类或方法 ...

  2. 新概念 Lesson 2 Sorry, sir.

    Is this your handbag? 这是你的手提包吗? Yes,it is. /No it isn't 人称代词的主格宾格 形容性物主代词的用法 Does the man get his um ...

  3. DownLoadImage

    Private Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA&quo ...

  4. 20170727xlVBA根据数据表和模板工作簿生成个人明细表工作簿

    Sub CreateTables() Dim Wb As Workbook Dim OpenWb As Workbook Dim Sht As Worksheet Dim Rng As Range D ...

  5. Jersey 2.x 从Maven Archetype 创建一个新项目

    创建 Jersey 工程需要使用 Apache 的 Maven 软件工程和管理工具.所有的Jersey产品模块都可以在 Maven中央库 中找到.这样的话 Jersey 可以非常容易和其他基于 Mav ...

  6. qbxt联赛集训d1t3

    题意 给出一个长度为n的序列,求所有区间的区间最小值乘区间最大值的和.(n<=1e5) solution:

  7. 『cs231n』作业3问题1选讲_通过代码理解RNN&图像标注训练

    一份不错的作业3资料(含答案) RNN神经元理解 单个RNN神经元行为 括号中表示的是维度 向前传播 def rnn_step_forward(x, prev_h, Wx, Wh, b): " ...

  8. length,lengthb,substr,substrb,instr小用

    --字符串的字符长度 select length('wm.dfw.士农工商.sda.人马ss.dfw.4.sdf.332.sf.qq.sd') from dual; --字符串的字节长度 select ...

  9. chrome plugins

    ehpomnigmfglbkmnboidmmhhmicfdmom_1_1_0知行-时间管理 必开 Adkill and Media Download Cnblogs Wz(博客园网摘) Kami - ...

  10. snapshot相关

    概述 Specify the number of days of snapshots to choose from Entering the number of days (n) will resul ...