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 ...
随机推荐
- Tree Generator™ CodeForces - 1149C (线段树,括号序列)
大意: 给定括号序列, 每次询问交换两个括号, 求括号树的直径. 用[ZJOI2007]捉迷藏的方法维护即可. #include <iostream> #include <algor ...
- (三)Lucene之删除更新文档以及luke的基本使用
一.demo 本例中采用单元测试,故在pom.xml中引入junit jar包 1.1 前提: public class IndexTest { /** *数据准备 */ private String ...
- Java BinarySearch
Java BinarySearch /** * <html> * <body> * <P> Copyright 1994-2018 JasonInternation ...
- 一篇文章彻底搞懂异步,同步,setTimeout,Promise,async
之前翻看别的大佬的博客看到了关于setTimeout,promise还有async执行顺序的文章.观看了几篇之后还是没有怎么看懂,于是自己开始分析代码,并整理了此文章,我相信通过此文章朋友们能对异步同 ...
- Mediawiki 子页链接无效的问题
添加下面的配置到 LocalSettings.php 中即可: # Enable subpages in the main namespace $wgNamespacesWithSubpages[NS ...
- 前端知识总结--js异步事件顺序
js中异步事件中容易混淆的 Promise 和 setTimeout 的执行顺序是怎样的? setTimeout(() => console.log(1), 0); new Promise(fu ...
- 栈 · 有getMin功能的栈O(1)
题面 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中的最小元素的操作. 要求 pop(), push(), getMin()时间复杂度都是O(1) 思路 1.准备两个栈,数据栈+最小元素 ...
- PHP基础——语法篇
<!-- 语句:通过 PHP,有两种在浏览器输出文本的基础指令:echo 和 print. --> <?php echo "Hello World!"; //PH ...
- c#系统预定义类型
- 【问题】bzip2 --version 2>&1 < /dev/null
https://unix.stackexchange.com/questions/230887/what-does-dev-null-mean https://stackoverflow.com/qu ...