计数套路题?但是我连套路都不会,,,

拿到这道题我一脸蒙彼,,,感谢@poorpool 大佬的博客的指点

先将第\(i\)位上的数字\(p_i\)向\(i\)连无向边,然后构成了一个有若干环组成的无向图,可以知道某个点包含它的有且仅有一个环,因为所有点度数都为2(自环的点度数也是2吧qwq)

那么我们的最终目标就是把这个图转换成有\(n\)个自环的图,相当于把排列排好顺序

考虑对于一个\(m\)个点的环,把它变成\(m\)个自环至少需要\(m-1\)步(相当于排列\((2,3...m,1)\)变成\((1,2,3...m)\),这至少需要\(m-1\)次交换)

设把一个\(m\)个点的环变成\(m\)个自环的方案数为\(f_m\).因为一次操作可以把一个环拆成两个环,设拆出来两个环大小为\(x,y\),那么拆环的方案数\(g(x,y)\)为$$g(x,y)=\begin{cases}x,\quad (x=y)\x+y, \quad others\end{cases} $$

就是对于每一个点,有两个点使得这一个点和那两个点中的一个进行交换操作可以分出大小为\(x,y\)的环,因为点对会被计算2次,所以方案为\(\frac{(x+y)*2}{2}=x+y\),如果\(x=y\),那么那两个点是同一点,所以方案要除以2

每个环之间的操作是不会相互影响的,所以可以交错进行操作,两个环贡献答案给一个大环时,两个环的操作交错所构成的排列数就是可重集的排列数(总元素个数阶乘除以每一中元素个数阶乘).综上,我们可以知道$$f_m=\sum_{i=1}^{\lfloor\frac{m}{2}\rfloor} g(i,m-i)f_if_{m-i}\frac{(m-2)!}{(i-1)!(m-i-1)!}$$

我们可以找出\(k\)个大小为\(a_1,a_2...a_k\)的环

把所有环的答案合并,同样每个环之间的操作是不会相互影响的,所以方案数要乘上一个可重集的排列数,可以得到$$ans=\prod_{i=1}^{k} f_{a_i}*\frac{(n-k)!}{\prod_{i=1}^{k}(a_i-1)!}$$

(注意边界,\(f_1=f_2=1\))

然而求\(f\)要\(O(n)\)的时间,总复杂度为\(O(nk)\)

考虑优化此算法,通过打表找规律可以发现\(f_i=i^{i-2}\)

然后求\(f\)只要要\(O(logn)\)了,爽!

然后就可以偷税的写代码了

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register using namespace std;
const LL mod=1000000009;
il LL rd()
{
re LL x=0,w=1;re char ch;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int to[200010],nt[200010],hd[100010],tot=1;
int vis[200010],a[100010],tt;
LL jc[100010],cj[100010]; //不要问我为什么把阶乘数组的逆元写成cj(逃
bool v[100010];
il void add(int x,int y)
{
++tot;to[tot]=y;nt[tot]=hd[x];hd[x]=tot;
++tot;to[tot]=x;nt[tot]=hd[y];hd[y]=tot;
}
il void dfs(int x,int o,int h)
{
if(!v[x]) ++a[o];v[x]=true;
for(int i=hd[x];i;i=nt[i])
{
if(vis[i]==h) continue;
vis[i]=vis[i^1]=h;
dfs(to[i],o,h);
}
}
il LL ksm(LL a,LL b)
{
if(b<=0) return 1; //i=1时,i-2会为-1 qwq
LL an=1;
while(b)
{
if(b&1) an=(an*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return an;
} int main()
{
jc[0]=cj[0]=1;
for(int i=1;i<=100000;i++) jc[i]=(jc[i-1]*i)%mod,cj[i]=ksm(jc[i],mod-2);
int T=rd();
for(int h=1;h<=T;h++)
{
tot=1;tt=0;
memset(a,0,sizeof(a));
memset(v,0,sizeof(v));
memset(hd,0,sizeof(hd));
int n=rd();
for(int i=1;i<=n;i++) add(i,rd());
for(int i=1;i<=n;i++)
if(!v[i]) dfs(i,++tt,h);
LL ans=jc[n-tt];
for(int i=1;i<=tt;i++) ans=((ans*ksm(a[i],a[i]-2))%mod*cj[a[i]-1])%mod;
printf("%lld\n",ans);
}
return 0;
}

luogu P4778 Counting swaps的更多相关文章

  1. 洛谷P4778 Counting swaps 数论

    正解:数论 解题报告: 传送门! 首先考虑最终的状态是固定的,所以可以知道初始状态的每个数要去哪个地方,就可以考虑给每个数$a$连一条边,指向一个数$b$,表示$a$最后要移至$b$所在的位置 显然每 ...

  2. P4778 Counting Swaps 题解

    第一道 A 掉的严格意义上的组合计数题,特来纪念一发. 第一次真正接触到这种类型的题,给人感觉好像思维得很发散才行-- 对于一个排列 \(p_1,p_2,\dots,p_n\),对于每个 \(i\) ...

  3. CH3602 Counting Swaps

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

  4. Counting swaps

    Counting swaps 给你一个1-n的排列,问用最少的交换次数使之变为递增排列的方案数\(mod\ 10^9+7\),1 ≤ n ≤ 10^5. 解 显然最少的交换次数不定,还得需要找到最小交 ...

  5. LFYZOJ 104 Counting Swaps

    题解 #include <iostream> #include <cstdio> #include <algorithm> #include <cmath&g ...

  6. lfyzoj104 Counting Swaps

    问题描述 给定你一个 \(1 \sim n\) 的排列 \(\{p_i\}\),可进行若干次操作,每次选择两个整数 \(x,y\),交换 \(p_x,p_y\). 请你告诉穰子,用最少的操作次数将给定 ...

  7. luoguP4778 Counting swaps

    题目链接 题解 首先,对于每个\(i\)向\(a[i]\)连边. 这样会连出许多独立的环. 可以证明,交换操作不会跨越环. 每个环内的点到最终状态最少交换步数是 \(环的大小-1\) 那么设\(f[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. 线段树合并 || 树状数组 || 离散化 || BZOJ 4756: [Usaco2017 Jan]Promotion Counting || Luogu P3605 [USACO17JAN]Promotion Counting晋升者计数

    题面:P3605 [USACO17JAN]Promotion Counting晋升者计数 题解:这是一道万能题,树状数组 || 主席树 || 线段树合并 || 莫队套分块 || 线段树 都可以写..记 ...

随机推荐

  1. Bootstrap自动定位浮标

    前面的话 Affix 插件主要功能就是通过插件给某个元素(需要固定的元素)添加或删除position:fixed,实现元素在浏览器窗口的粘性固定效果.本文将详细介绍Bootstrap自动定位浮标 基本 ...

  2. httprequest存储的是字符内容 而文本内容是以字节形式上传的;所以普通的取值方式无法从httprequest取到值

    httprequest存储的是字符内容 而文本内容是以字节形式上传的;所以普通的取值方式无法从httprequest取到值

  3. BZOJ5018[Snoi2017]英雄联盟——DP

    题目描述 正在上大学的小皮球热爱英雄联盟这款游戏,而且打的很菜,被网友们戏称为「小学生」.现在,小皮球终于受不 了网友们的嘲讽,决定变强了,他变强的方法就是:买皮肤!小皮球只会玩N个英雄,因此,他也只 ...

  4. BZOJ1785[USACO 2010 Jan Gold 3.Cow Telephones]——贪心

    题目描述 奶牛们建立了电话网络,这个网络可看作为是一棵无根树连接n(1 n 100,000)个节点,节点编号为1 .. n.每个节点可能是(电话交换机,或者电话机).每条电话线连接两个节点.第i条电话 ...

  5. Leetcode 237.删除链表中的节点 By Python

    请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点. 现有一个链表 -- head = [4,5,1,9],它可以表示为: 4 -> 5 -> 1 - ...

  6. [luogu1373]小a和uim之大逃离【动态规划】

    传送门:https://www.luogu.org/problemnew/show/P1373 定义状态是:\(f[i][j][h][0..1]\)表示在\([i,j]\)两个人相差为h,让某一个人走 ...

  7. Windows Server 2008配置Network Load Balancing(服务群集)

          最近配置SharePoint 2013 WFE 时,客户提到要让多台WFE能load balance,于是研究了下Network Load Balancing.       当把一台服务器 ...

  8. luogu2178/bzoj4199 品酒大会 (SA+单调栈)

    他要求的就是lcp(x,y)>=i的(x,y)的个数和a[x]*a[y]的最大值 做一下后缀和,就只要求lcp=i的了 既然lcp(x,y)=min(h[rank[x]+1],..,[h[ran ...

  9. sklearn 总结

    一张思维导图总结一下用到的大体模块:

  10. Logstash解析Json array

    logstash解析json数组是一种常见的需求,我以网上一组数据为例来描述 我们的数据test.json内容如下:(此处我linux上的json文本需要是compact的) {"type& ...