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. 关于键盘KeyDown事件

    if (e.KeyValue==13) //如果键盘的值等于13 这里面的13是enter键 textBox2.Focus(); //焦点就跑到textbox2上面

  2. Vue生命周期学习

    转自https://www.w3cplus.com/vue/vue-instances-and-life-cycles.html Vue实例虽然没有完全遵循MVVM模型,但Vue的设计无疑受到了它的启 ...

  3. 程序员必备技能:代码审查 (Google牛人谈Code Review)

    在上一篇博客里我暗示自己将不在为Google工作. 我还没有决定好去哪儿-有几个非常不错的工作机会让我选择.鉴于这段时间内我不受雇于任何公司,我想我可以写点和专业相关的东西,这些东西很有趣,但是如果我 ...

  4. [javaSE] 数据结构(栈)

    栈(stack)是一种线性存储结构,有以下特点: 1.栈中数据是按照先进后出的方式进出栈的 2.向栈中添加删除元素时,只能从栈顶进行操作 使用数组实现栈 定义一个类ArrayStack 实现入栈方法p ...

  5. 用户登录注册(安全)(常规、FB、google、paypal) 实战

    /* 用户登录界面 */elseif ($action == 'login'){    if($_SESSION['user_id'])    {        ecs_header("Lo ...

  6. 17、多线程 (Thread、线程创建、线程池)

    进程概念 *A:进程概念 *a:进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行, 即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程的概念 *A:线程的概念 *a ...

  7. No Mapping For GET "xxx.do"

    今天写的一个form表单提交时总是报错找不到mapping,form如下: <form action="toUpdate.do" method="post" ...

  8. Java8实战Lambda和Stram API学习

    public  class Trader{        private String name;    private String city; public Trader(String n, St ...

  9. 【SSH网上商城项目实战16】Hibernate的二级缓存处理首页的热门显示

    转自:https://blog.csdn.net/eson_15/article/details/51405911 网上商城首页都有热门商品,那么这些商品的点击率是很高的,当用户点击某个热门商品后需要 ...

  10. HBase—列族数据库的术语

    1. 列族数据库的基本组件 键空间,行键,列,列族 2. 什么是键空间 keyspace? 键空间 keyspace 是列族数据库的顶级数据结构,它在逻辑上能够容纳列族,行键以及与之相关的其他数据结构 ...