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. Swift函数_默认参数

    swift中提供了默认参数功能,在声明函数时给参数指定默认值. 例: func inputStudentInfo(name:String,age:Int="26") { print ...

  2. 三、curator recipes之共享的可重入读写锁

    简介 curator实现了跨JVM的可重入读写互斥锁.它使用zookeeper去进行加锁,所以指定相同路径的处理线程将会基于“公平锁”的机制去竞争锁资源. 读写锁包含了读锁.写锁两个,它们的互斥关系如 ...

  3. DIRECTORY_SEPARATOR 目录分隔符 php内置变量

    转自http://www.cnblogs.com/timelesszhuang/p/3814878.html 在windows我们习惯性的使用“\”作为文件分隔符,但是在linux上系统不认识这个标识 ...

  4. [SDOI2014]旅行解题报告

    题目描述 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. 为了方便,我 ...

  5. sublime3下载安装及常用插件、浏览器预览设置

    之前与学习前端有关的软件都安装在了实验室电脑上,最近由于要放寒假(也许我寒假回去会学习呢),于是得在笔记本电脑上重新安装一遍.几个软件各种出错,花了一下午才安装好,必须记录下来啊! 这篇文章主要介绍s ...

  6. xfs参数简介

    age_buffer_centisecs age_buffer_centisecs:(Min: 100  Default: 1500  Max: 720000) 多长时间设置为脏数据 xfsbufd_ ...

  7. A memory map of an object

    Phone类 package com.itheima_02; /* * 手机类: * 成员变量:品牌,价格,颜色... * 成员方法:打电话,发短信... */ public class Phone ...

  8. linux下C语言三种get输入方式

    第一种:scanf() #include "stdio.h" #include "string.h" int main() { ]; scanf("% ...

  9. MyBatis基本配置和实践(二)

    一.前言 从上一篇文章的junit单元测试环节可以看到,每一次调用MyBatis需要先加载SqlMapConfig.xml文件,再通过SqlSessionFactoryBuilder创建SqlSess ...

  10. laravel middleware

    当你使用larvel创建一个相对比较复杂的web网站时,往往你的routes文件就会变得很庞大.一般来说在开始网站编码之前,最好做一个整体规划,把这些route逻辑上划分为不同的group,每一个gr ...