luoguP4778 Counting swaps
题解
首先,对于每个\(i\)向\(a[i]\)连边.
这样会连出许多独立的环.
可以证明,交换操作不会跨越环.
每个环内的点到最终状态最少交换步数是 \(环的大小-1\)
那么设\(f[i]\)表示环大小为\(i\)的方案数
则
\]
其中
\]
打标可以发现\(f[n] = n^{n-2}(n≠1)\)
那么假设有\(k\)个环,第\(i\)个环大小为\(a[i]\)
则
\]
\(T\)是把\(n-k\)步分进每个环的方案数
\(T=\frac{(n-k)!}{\prod(a[i]-1)!}\)
还有另一种方法算\(T\)(具体看代码)
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, Mod = 1e9 + 9;
int fpow(int a, int b) {
if (b <= 0) return 1;
int res = 1;
for (; b; b >>= 1, a = 1ll * a * a % Mod) if (b & 1) res = 1ll * res * a % Mod;
return res;
}
bool vis[N];
int to[N], a[N];
int dfs(int x) {
vis[x] = 1;
if (vis[to[x]]) return 1;
else return 1 + dfs(to[x]);
}
int fac[N], ifac[N];
int C(int n, int m) {
if (n < m) return 0;
return 1ll * fac[n] * ifac[n - m] % Mod * ifac[m] % Mod;
}
void solve() {
int n, ans = 1;
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &to[i]);
memset(vis, 0, sizeof(vis));
int len = 0;
for (int i = 1; i <= n; i++)
if (!vis[i])
a[++len] = dfs(i);
// for (int i = 1; i <= len; i++) ans = 1ll * ans * fpow(a[i], a[i] - 2) % Mod * ifac[a[i] - 1] % Mod;
for (int i = 1, sum = 0; i <= len; sum += a[i++] - 1)
ans = 1ll * ans * fpow(a[i], a[i] - 2) % Mod * C(n - sum - len, a[i] - 1) % Mod;
printf("%d\n", /*1ll * ans * fac[n - len] % Mod*/ans);
return ;
}
int main() {
int T;
scanf("%d", &T);
fac[0] = 1;
for (int i = 1; i <= 100000; i++) fac[i] = 1ll * fac[i - 1] * i % Mod;
ifac[100000] = fpow(fac[100000], Mod - 2);
for (int i = 100000; i >= 1; i--) ifac[i - 1] = 1ll * ifac[i] * i % Mod;
while (T--) solve();
return 0;
}
luoguP4778 Counting swaps的更多相关文章
- CH3602 Counting Swaps
题意 3602 Counting Swaps 0x30「数学知识」例题 背景 https://ipsc.ksp.sk/2016/real/problems/c.html Just like yeste ...
- Counting swaps
Counting swaps 给你一个1-n的排列,问用最少的交换次数使之变为递增排列的方案数\(mod\ 10^9+7\),1 ≤ n ≤ 10^5. 解 显然最少的交换次数不定,还得需要找到最小交 ...
- 洛谷P4778 Counting swaps 数论
正解:数论 解题报告: 传送门! 首先考虑最终的状态是固定的,所以可以知道初始状态的每个数要去哪个地方,就可以考虑给每个数$a$连一条边,指向一个数$b$,表示$a$最后要移至$b$所在的位置 显然每 ...
- luogu P4778 Counting swaps
计数套路题?但是我连套路都不会,,, 拿到这道题我一脸蒙彼,,,感谢@poorpool 大佬的博客的指点 先将第\(i\)位上的数字\(p_i\)向\(i\)连无向边,然后构成了一个有若干环组成的无向 ...
- LFYZOJ 104 Counting Swaps
题解 #include <iostream> #include <cstdio> #include <algorithm> #include <cmath&g ...
- lfyzoj104 Counting Swaps
问题描述 给定你一个 \(1 \sim n\) 的排列 \(\{p_i\}\),可进行若干次操作,每次选择两个整数 \(x,y\),交换 \(p_x,p_y\). 请你告诉穰子,用最少的操作次数将给定 ...
- P4778 Counting Swaps 题解
第一道 A 掉的严格意义上的组合计数题,特来纪念一发. 第一次真正接触到这种类型的题,给人感觉好像思维得很发散才行-- 对于一个排列 \(p_1,p_2,\dots,p_n\),对于每个 \(i\) ...
- 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 ...
- 萌新笔记——Cardinality Estimation算法学习(二)(Linear Counting算法、最大似然估计(MLE))
在上篇,我了解了基数的基本概念,现在进入Linear Counting算法的学习. 理解颇浅,还请大神指点! http://blog.codinglabs.org/articles/algorithm ...
随机推荐
- java中单双引号的区别
单引号: 单引号包括的是单个字符,表示的是char类型.例如: char a='1' 双引号: 双引号可以包括0个或者多个字符,表示的是String类型. 例如: String s="ab ...
- 面试经典算法:优先队列,最大堆,堆排序,左偏树Golang实现
堆排序 使用优先队列-最小/最大堆可实现. 优先队列 优先队列是一种能完成以下任务的队列:插入一个数值,取出最小的数值(获取数值,并且删除).优先队列可以用二叉树来实现,我们称这种为二叉堆. 最小堆 ...
- (十六)Hibernate中的延迟加载
一.什么是延迟加载 为了节省Hibernate加载对象的性能节销,在Hibernate中真正需要用到这个对象时,才会发出 SQL语句来抓取这个对象.这一个过程称为延迟加载. 二.延迟加载 ...
- GNU,GPL与自由软件
GNU 是 Richard Stallman(理查德·斯托曼)创建的一个项目,not unix GPL(General Public License),GNU通用公共许可证.书面上的协议 自由软件与开 ...
- default(Nullable(type)) vs default(type)
default(Nullable<long>) == null default(long?) == null default(long) == 0L
- ES6--JavaScript扩展知识点(let、const、解构)
一,ES2015(ES6)新增了两个声明变量的关键字:let.const let:只在代码块内{}有效,不可重复声明,不会提前初始化 1.只在代码块内有效 { let a = 1; var b = 2 ...
- 移动端适配flexible.js
npm install lib-flexible --save npm install px2rem-loader --save-dev
- 你所不知道的 Console
1.凡人视角 打印字符串 代码: console.log("I am a 凡人"); 打印提示消息 代码: console.info("Yes, you arm a 凡人 ...
- 巧用flex(一)
在开发中我们经常遇到一个页面头部内容固定顶部,中间内容可滚动的需求,一般的逻辑就是把头部内容通过position以及z-index固定位置,提高层级,然后中间内容设置距离顶部一定距离,这样的效果是侧边 ...
- K2 BPM_【解决方案】从流程梳理到落地,K2为企业打造流程管理闭环_全业务流程管理专家
很多企业在进行流程管理体系建设的过程中,往往急于求成,还没有理清楚要“做什么”和“怎么做”,就开始大刀阔斧地进行改革优化.管理目标.建设标准的不统一,使得体系建设之间内容重复.要求冲突等现象层出不穷. ...