神仙题。

排列计数,一种常见的做法是 \(i\) 向 \(p_i\) 连边。

然而这里这个就逼迫我们只能从 \(i\) 向 \(a_i\) 连边。

不过没关系,考虑从 \(i\) 向 \(p_i\) 连边的图(为方便叫 \(G_1\))和从 \(i\) 向 \(a_i\) 连边的图(为方便叫 \(G_2\))的区别。

首先 \(G_1\) 中每个点入度和出度都是 \(1\),所以是一堆环构成的。

考虑一个环:(下面建议画图,懒的建议看 litble 学姐的博客,自己不敢直接把图拿过来)

  • 如果上面所有点都满足 \(p_i=a_i\),那么这个环在 \(G_2\) 中也出现了,长得一样。
  • 如果上面所有点都满足 \(p_{p_i}=a_i\),且这个环长度为奇数,那么有一个相同长度的环在 \(G_2\) 中出现了,但是长得不一样。
  • 如果上面所有点都满足 \(p_{p_i}=a_i\),且这个环长度为偶数,那么有两个长度都为这个环长度的一半的环在 \(G_2\) 中出现了。
  • 如果上面的点又有满足 \(p_i=a_i\) 的,又有满足 \(p_{p_i}=a_i\) 的,那么会有一个点数相同的基环内向树在 \(G_2\) 中出现。(这种情况比较复杂,等会再说)

现在知道了 \(G_2\) ,问 \(G_1\) 的方案数。

环和基环树独立。先看环。

令长度为 \(i\) 的环有 \(cnt_i\) 个。每个环要么是单独在 \(G_1\) 中出现,要么是与另一个环拼成一个大环在 \(G_1\) 中出现。

枚举与别的环一起拼的环的个数 \(2j\),那么把下面这些全步乘起来:

  • \(j\ne 0\) 时,先选出这些环,\(\binom{cnt_i}{2j}\);
  • \(j\ne 0\) 时,然后想象成是个二分图,枚举左边的环是哪些,再把右边的环分给左边的环。注意实际上没有顺序,所以要再除掉一堆 \(2\)。\(\frac{\binom{2j}{j}j!}{2^j}\);
  • \(j\ne 0\) 时,每对环有 \(i\) 种拼法,\(i^j\);
  • \(i\) 为奇数且 \(i\ne 1\) 时,没有与别的环拼起来的环可以以两种形态在 \(G_1\) 中出现,\(2^{cnt_i-2j}\)。

再看基环树。基环树之间也相互独立。

挂在基环树上的一堆链要压到环上。图的话,建议继续看学姐的博客。

抓比较重要的几点来说:1、每条链不能重叠,所以压链的话不能超过上一个有链的点。2、如果不考虑 1 中的限制,每条链有两种压法,上面的第一个点在 \(G_1\) 中直接连向 \(u\) 和两步连向 \(u\)。

所以说,每条链的压法只有 \(0,1,2\),且互相独立。直接乘起来。

一些无解情况也可以很简单判了:在环上的点入度 \(\le 2\),不在环上的点入度 \(\le 1\)。联想一下基环树的方案数算法应该很好理解。

时间复杂度 \(O(n\log n)\),如果有闲心也可以做到 \(O(n)\)。

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010,mod=1000000007,inv2=500000004;
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
int x=0,f=0;char ch=getchar();
while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return f?-x:x;
}
int n,a[maxn],deg[maxn],ans=1,stk[maxn],tp,q[maxn],h,r,len[maxn],seq[maxn],tot,cnt[maxn];
int fac[maxn],inv[maxn],invfac[maxn];
bool vis[maxn],ins[maxn],cyc[maxn];
void dfs(int u){
if(vis[u]){
if(ins[u]){
ROF(i,tp,1){
cyc[stk[i]]=true;
if(stk[i]==u) break;
}
}
return;
}
vis[u]=ins[u]=true;
stk[++tp]=u;
dfs(a[u]);
ins[u]=false;
}
bool dfs2(int u){
if(vis[u]) return true;
vis[u]=true;
seq[++tot]=len[u];
return dfs2(a[u]) && !len[u];
}
inline int C(int n,int m){
return 1ll*fac[n]*invfac[m]%mod*invfac[n-m]%mod;
}
inline int qpow(int a,int b){
int ans=1;
for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) ans=1ll*ans*a%mod;
return ans;
}
int main(){
n=read();
FOR(i,1,n) a[i]=read(),deg[a[i]]++;
FOR(i,1,n) dfs(i);
FOR(i,1,n) if(cyc[i] && deg[i]>=3|| !cyc[i] && deg[i]>=2) return puts("0"),0;
h=1;r=0;
FOR(i,1,n) if(!deg[i]) q[++r]=i;
while(h<=r){
int u=q[h++];
len[a[u]]=len[u]+1;
if(!cyc[a[u]]) q[++r]=a[u];
}
MEM(vis,0);
FOR(i,1,n) if(cyc[i] && !vis[i]){
tot=0;
if(dfs2(i)) cnt[tot]++;
else{
int pre=0;
FOR(j,1,tot) if(seq[j]){
if(pre){
int at=j-seq[j];
if(at<pre) return puts("0"),0;
if(at>pre && tot>=2) ans=2*ans%mod;
}
pre=j;
}
FOR(j,1,tot) if(seq[j]){
int at=j-seq[j]+tot;
if(at<pre) return puts("0"),0;
if(at>pre && tot>=2) ans=2*ans%mod;
break;
}
}
}
fac[0]=fac[1]=inv[1]=invfac[0]=invfac[1]=1;
FOR(i,2,n){
fac[i]=1ll*fac[i-1]*i%mod;
inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod;
invfac[i]=1ll*invfac[i-1]*inv[i]%mod;
}
FOR(i,1,n) if(cnt[i]){
int s=0;
FOR(j,0,cnt[i]/2){
int x=1ll*C(cnt[i],2*j)*C(2*j,j)%mod*fac[j]%mod;
if(j) x=1ll*x*qpow(inv2,j)%mod*qpow(i,j)%mod;
if(i%2==1 && i!=1) x=1ll*x*qpow(2,cnt[i]-2*j)%mod;
s=(s+x)%mod;
}
ans=1ll*ans*s%mod;
}
printf("%d\n",ans);
}

AGC008E Next or Nextnext(组合计数,神奇思路)的更多相关文章

  1. [总结]数论和组合计数类数学相关(定理&证明&板子)

    0 写在前面 0.0 前言 由于我太菜了,导致一些东西一学就忘,特开此文来记录下最让我头痛的数学相关问题. 一些引用的文字都注释了原文链接,若侵犯了您的权益,敬请告知:若文章中出现错误,也烦请告知. ...

  2. bzoj 2281 [Sdoi2011]黑白棋(博弈+组合计数)

    黑白棋(game) [问题描述] 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色 ...

  3. WC集训DAY2笔记 组合计数 part.1

    目录 WC集训DAY2笔记 组合计数 part.1 基础知识 组合恒等式 错排数 卡特兰数 斯特林数 伯努利数 贝尔数 调和级数 后记 补完了几天前写的东西 WC集训DAY2笔记 组合计数 part. ...

  4. BZOJ1079 [SCOI2008]着色方案[组合计数DP]

    $有a_{1}个1,a_{2}个2,...,a_{n}个n(n<=15,a_{n}<=5),求排成一列相邻位不相同的方案数.$ 关于这题的教训记录: 学会对于复杂的影响分开计,善于发现整体 ...

  5. BZOJ 4555: [Tjoi2016&Heoi2016]求和 [分治FFT 组合计数 | 多项式求逆]

    4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...

  6. BZOJ 4555: [Tjoi2016&Heoi2016]求和 [FFT 组合计数 容斥原理]

    4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...

  7. 【BZOJ5491】[HNOI2019]多边形(模拟,组合计数)

    [HNOI2019]多边形(模拟,组合计数) 题面 洛谷 题解 突然特别想骂人,本来我考场现切了的,结果WA了几个点,刚刚拿代码一看有个地方忘记取模了. 首先发现终止态一定是所有点都向\(n\)连边( ...

  8. 【BZOJ5323】[JXOI2018]游戏(组合计数,线性筛)

    [BZOJ5323][JXOI2018]游戏(组合计数,线性筛) 题面 BZOJ 洛谷 题解 显然要考虑的位置只有那些在\([l,r]\)中不存在任意一个约数的数. 假设这样的数有\(x\)个,那么剩 ...

  9. 【BZOJ5305】[HAOI2018]苹果树(组合计数)

    [BZOJ5305][HAOI2018]苹果树(组合计数) 题面 BZOJ 洛谷 题解 考虑对于每条边计算贡献.每条边的贡献是\(size*(n-size)\). 对于某个点\(u\),如果它有一棵大 ...

  10. 【BZOJ3142】[HNOI2013]数列(组合计数)

    [BZOJ3142][HNOI2013]数列(组合计数) 题面 BZOJ 洛谷 题解 唯一考虑的就是把一段值给分配给\(k-1\)天,假设这\(k-1\)天分配好了,第\(i\)天是\(a_i\),假 ...

随机推荐

  1. UnitTest和Developer

    UnitTest对项目很重要,这是很多developer都明白的道理,可是真的让所有的developer对自己的代码写UnitTest,似乎是不可能的. developer完全可以以已经有很多task ...

  2. mysql关联两张表时的编码问题

    Mysql关联两张表时,产生错误提示Illegal mix of collations 1.先用工具把数据库.两张表的编码方式改变 2.这步很重要,需要改变字段的编码方式. ALTER TABLE ` ...

  3. mathematica练习程序(曲线的曲率与挠率)

    曲线的曲率k表示曲线的弯曲程度. 计算公式: 曲线的挠率tao表示曲率平面的扭曲程度,平面曲线挠率为0. 计算公式: 这里r代表曲线方程,比如有如下曲线方程:r={a*cos(t),a*sin(t), ...

  4. UOJ #450. 【集训队作业2018】复读机

    前置知识单位根反演自己去浅谈单位根反演看(此外可能需要一定的生成函数的姿势) 首先一看\(d\)这么小,那我们来分类讨论一下吧 当\(d=1\)时,显然答案就是\(k^n\) 当\(d=2\)时,如果 ...

  5. 使用php开发,基于swoole扩展开发的工具 swoole-crontab 作业/任务调度

    Swoole-Crontab(基于Swoole扩展) 1.概述 基于swoole的定时器程序,支持秒级处理. 异步多进程处理. 完全兼容crontab语法,且支持秒的配置,可使用数组规定好精确操作时间 ...

  6. 基于 H5 + WebGL 实现的地铁站 3D 可视化系统

    前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...

  7. Netty — 线程模型

    一.前言 众所周知,netty是高性能的原因源于其使用的是NIO,但是这只是其中一方面原因,其IO模型上决定的.另一方面源于其线程模型的设计,良好的线程模型设计,能够减少线程上下文切换,减少甚至避免锁 ...

  8. IDA中查看某函数引用问题

    按X键,即可列出哪个部分引用该函数.

  9. Spring Security 教程 大牛的教程

    https://www.iteye.com/blog/elim-2247073 Spring Security 教程 Spring Security(20)——整合Cas Spring Securit ...

  10. Python爬取6271家死亡公司数据,看十年创业公司消亡史

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 朱小五 凹凸玩数据 PS:如有需要Python学习资料的小伙伴可以加 ...