Counting swaps

给你一个1~n的排列,问用最少的交换次数使之变为递增排列的方案数\(mod\ 10^9+7\),1 ≤ n ≤ 10^5。

显然最少的交换次数不定,还得需要找到最小交换次数,而考虑到交换为复杂的过程,考虑状态的性质,所以不难想到画出,+为箭头指向方向

 _   _
| + | +
2 1 4 3
+ | + |
|_| |_|

于是你会发现实际上我们的变换为递增序列,即把所有的环都变成自环,而交换两个数字即拆环,所以不难知道,一个环拆掉的最少的次数为环的大小-1(因为你对一个环进行一次交换操作,就变成了两个环,以此类推,拆成n个环,要操作n-1次)。

有了这样一个想法,于是考虑环的组合计数问题的方法,可以以拆环为状态划分来设递推方程,于是设\(f[i]\)表示长度为i的环的变成全部是自环的最少操作次数的方案数,拆成两个环又有不同的拆分方式,于是设\(T[i][j]\)表示拆成两个长i,j的环的方案数,于是我们有

\[T[i][j]=i==j?i+j>>1:i+j
\]

\[f[i]=\sum_{j=1}^{[i/2]}f[j]\times f[i-j]\times T[j][i-j]\times\frac{(i-1)!}{(j-1)!(i-j-1)!}
\]

于是,设初始序列为长\(l_1,l_2...,l_m\)的环构成的,易知

\[ans=(n-m)!\prod_{i=1}^mf[l_i]\frac{1}{(l_i-1)!}
\]

但是对于f找规律,我们发现\(f[i]=i^{i-2}\),于是我们可以利用矩阵快速幂,时间复杂度应为\(O(nlog(n))\)。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
#define ll long long
#define yyb 1000000009
#define lsy 1000000007
#define _ putchar('\n')
using namespace std;
int num[100001];
bool check[100001];
ll dp[100001],jc[100001],jv[100001];
il ll pow(ll,ll);
il void prepare();
template<class free>void pen(free);
template<class free>il void read(free&);
int main(){
int cjx,i,j,n,len,tot;ll ans;
prepare(),read(cjx);
while(cjx--){
read(n),memset(check,0,sizeof(check));
for(i=1;i<=n;++i)read(num[i]);tot&=0,ans=1;
for(i=1;i<=n;++i)
if(!check[i]){
j=i,++tot,len&=0;
do j=num[j],++len,check[j]|=true;
while(i!=j);
ans=ans*dp[len]%yyb*jv[len-1]%yyb;
}ans=ans*jc[n-tot]%yyb,pen(ans),_;
}
return 0;
}
template<class free>
void pen(free x){
if(x>9)pen(x/10);putchar(x%10+48);
}
il ll pow(ll x,ll y){
ll ans(1);
while(y){
if(y&1)ans=ans*x%yyb;
x=x*x%yyb,y>>=1;
}return ans;
}
void prepare(){
ri int i,j;jc[1]=jc[0]=jv[1]=jv[0]=dp[1]=1;
for(i=2;i<=100000;++i)
jc[i]=jc[i-1]*i%yyb,jv[i]=
pow(jc[i],lsy),dp[i]=pow(i,i-2);
}
template<class free>
il void read(free& x){
x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}

Counting swaps的更多相关文章

  1. CH3602 Counting Swaps

    题意 3602 Counting Swaps 0x30「数学知识」例题 背景 https://ipsc.ksp.sk/2016/real/problems/c.html Just like yeste ...

  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. Html-完整表格

    表头th 特殊的单元格:加粗.居中 它的用户是取代td的位置即可 <table border="2"> <tr> <th>姓名</th&g ...

  2. IIS利用X-Forwarded-For获得来访者的真实IP

    https://help.aliyun.com/knowledge_detail/37948.html

  3. 使用nodeJs在本地搭建最简单的服务

    在搭建web服务器之前,需要先安装node.js 安装后node.js,接下来就需要安装http的镜像文件 一:本机安装软件 下载最新的NodeJs,进行安装.一直点击下一步就可以了.然后就可以查看安 ...

  4. 一、JDBC基础示例

    一.简介 JDBC全称叫做Java database connectivity,直译为Java语言的数据库连接.它主要针对于支持结构化查询语言(SQL)的数据源,与Java程序连接并操作数据. JDB ...

  5. MapReduce详解和WordCount模拟

    最早接触大数据,常萦绕耳边的一个词「MapReduce」.它到底是什么,能做什么,原理又是什么?且听下文讲解. 是什么 MapReduce 即是一个编程模型,又是一个计算框架,它充分采用了分治的思想, ...

  6. hdu 1075 What Are You Talking About 字典树模板

    What Are You Talking About Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/204800 K ...

  7. Java 类 ThreadLocal 本地线程变量

    前言:工作中将要使用ThreadLocal,先学习总结一波.有不对的地方欢迎评论指出. 定义 ThreadLocal并不是一个Thread,而是Thread的局部变量.这些变量不同于它们的普通对应物, ...

  8. python_tensorflow_Django实现逻辑回归

    1.工程概要 2.data文件以及input_data文件准备 链接:https://pan.baidu.com/s/1EBNyNurBXWeJVyhNeVnmnA 提取码:4nnl 3.logiss ...

  9. 用CSS3/JS绘制自己想要的按钮

    我认为按钮的绘制分以下三个步骤 第一步,绘制按钮的轮廓 选择合适的html标签,设置轮廓的CSS /* html代码 */ <a href="#" class="b ...

  10. 安卓app开发-03-项目的基本开发步骤

    android项目的基本开发步骤 这里分享一下开发 安卓 app 的流程,当然有些感觉不必要,其实不然,前期工作也是极为重要的额,就像开发的时候如果目标不对的话,到后期后很迷的,所以一定要提前做好规划 ...