题面传送门

一道挺有意思的题罢……

首先看到这种与置换乘法相关的题,首先把这些置换拆成一个个置换环,假设输入的置换有 \(m\) 个置换环,大小分别为 \(s_1,s_2,\cdots,s_m\),显然置换环与置换环的顺序是不影响的,因此我们只用考虑它的大小即可。

其次我们考虑对于一个置换,我们来考虑对其进行 \(k\) 次幂后会得到什么。手玩几组数据就可以发现,原来不在同一个置换环中的元素,进行 \(k\) 次幂后,肯定也不会在同一个置换环中,而有的原本在同一个置换环中的元素进行 \(k\) 次幂后会被拆开,具体来说,对于一个大小为 \(s\) 的置换环,进行 \(k\) 次幂后会拆成 \(\gcd(s,k)\) 个等大小的置换环,道理很明白,对于一个元素,你每次绕着置换环走 \(k\) 步,显然 \(\dfrac{s}{\gcd(s,k)}\) 次就会回到源点,因此 \(k\) 次幂后拆出的置换环中,单个置换环大小就是 \(\dfrac{s}{\gcd(s,k)}\)。

也就是说 \(s_1,s_2,\cdots,s_m\) 中有一些大小相同的置换环能拼起来,显然不同大小的置换环的方案数是独立的,因此我们可以分别求出每个大小的置换环拼起来的方案数再用乘法原理乘起来。考虑设 \(c_i\) 表示大小为 \(i\) 的置换环有多少个,那么根据之前的结论 \(j\) 个大小为 \(i\) 的置换环能够拼起来当且仅当 \(\gcd(ij,k)=j\)。那么怎么求大小为 \(i\) 的置换环拼起来有多少种方案呢?这时候就要用到 \(dp\) 了,我们设 \(dp_j\) 表示用了 \(j\) 个大小为 \(i\) 的置换环的方案数,考虑转移,我们枚举第 \(j\) 个大小为 \(i\) 的置换环跟多少个环在一起拼成大环,假设为 \(r\) 个,那么 \(dp_i=\sum\limits_rdp_{i-r}\dbinom{i-1}{r-1}f(r,i)[\gcd(ir,k)=r]\),其中 \(f(r,i)\) 表示将 \(r\) 个大小为 \(i\) 的置换环拼起来的方案数,注意到 \(\gcd(ir,k)=r\Rightarrow r\mid k\),因此枚举的 \(r\) 必须是 \(k\) 的约数,又 \(\sum c_i=m\) 是 \(\mathcal O(n)\) 级别的,因此这样暴力 DP 总枚举量是 \(n·d(k)\) 的。

最后考虑怎样求 \(f(r,i)\),由于最后拼成的是一个环,因此我们钦定第一个环的第一个元素必须在第一个位置,否则会算重,将剩余 \(r-1\) 个环填入剩余 \(r-1\) 个位置有 \((r-1)!\) 种,剩余 \((r-1)!\) 个环也可自由旋转,方案数为 \(i^{r-1}\),因此 \(f(r,i)=(r-1)!\times i^{r-1}\),随便算算即可。

时间复杂度 \(n·d(k)·\log n\),因为计算 \(f(r,i)\) 时涉及快速幂。

const int MAXN=1e5;
const int MOD=998244353;
int n,p[MAXN+5],c[MAXN+5],dp[MAXN+5],vis[MAXN+5];
int fac[MAXN+5],ifac[MAXN+5];vector<int> f;
int gcd(int x,int y){return (!y)?x:gcd(y,x%y);}
int qpow(int x,int e){
int ret=1;
for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
return ret;
}
void init_fac(int n){
for(int i=(fac[0]=ifac[0]=ifac[1]=1)+1;i<=n;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i-1]*ifac[i]%MOD;
}
int binom(int n,int k){return 1ll*fac[n]*ifac[k]%MOD*ifac[n-k]%MOD;}
int main(){
scanf("%d",&n);init_fac(n);int ans=1;
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
for(int i=1;i<=n;i++) if(n%i==0) f.pb(i);
for(int i=1;i<=n;i++) if(!vis[i]){
int siz=0;for(int j=i;!vis[j];j=p[j]) vis[j]=1,siz++;
c[siz]++;
}
for(int i=1;i<=n;i++){
dp[0]=1;
for(int j=1;j<=c[i];j++){
dp[j]=0;
for(int k=0;k<f.size()&&f[k]<=j&&i*f[k]<=n;k++)
if(gcd(i*f[k],n)==f[k]){
dp[j]=(dp[j]+1ll*dp[j-f[k]]*binom(j-1,f[k]-1)%MOD*
fac[f[k]-1]%MOD*qpow(i,f[k]-1))%MOD;
}
} ans=1ll*ans*dp[c[i]]%MOD;
} printf("%d\n",ans);
return 0;
}

洛谷 P4709 - 信息传递(置换+dp)的更多相关文章

  1. 洛谷P2661 信息传递(最小环,并查集)

    洛谷P2661 信息传递 最小环求解采用并查集求最小环. 只适用于本题的情况.对于新加可以使得两个子树合并的边,总有其中一点为其中一棵子树的根. 复杂度 \(O(n)\) . #include< ...

  2. [NOIP2015] 提高组 洛谷P2661 信息传递

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

  3. 洛谷 P2661 信息传递 Label:并查集||强联通分量

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

  4. 洛谷P2661 信息传递==coedevs4511 信息传递 NOIP2015 day1 T2

    P2661 信息传递 题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知 ...

  5. 洛谷 P2661 信息传递(并查集 & 最小环)

    嗯... 题目链接:https://www.luogu.org/problemnew/show/P2661 这道题和一些比较水的并查集不太一样,这道题的思路就是用并查集来求最小环... 首先,如果我们 ...

  6. NOIP2015提高组T2 洛谷P2661 信息传递

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

  7. 洛谷——P2661 信息传递

    https://www.luogu.org/problem/show?pid=2661#sub 题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其 ...

  8. 洛谷 P2661 信息传递 题解

    P2661 信息传递 题目描述 有 \(n\) 个同学(编号为 \(1\) 到 \(n\) )正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为 \(i\) 的同学的信息传 ...

  9. 洛谷p2661信息传递题解

    题目 这个题一眼看上去就是用并查集求最小环. 我们可以设两个数组分别是f,d分别表示该点的爸爸和该点到祖先的距离. 当该点的爸爸等于他时,那他肯定就是祖先. 此时信息就肯定传递完了,此时的整个图中(我 ...

随机推荐

  1. 2021.10.26考试总结[冲刺NOIP模拟16]

    T1 树上的数 \(DFS\)一遍.结构体存边好像更快? \(code:\) T1 #include<bits/stdc++.h> using namespace std; namespa ...

  2. Spring MVC:DispatchServlet类

    Spring MVC架构 Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就已包含在Spring框架中.传统的模型层被拆分为了业务层(Service)和数据访问层 ...

  3. C++实现红黑树

    红黑树的应用: 利用key_value对,快速查找,O(logn) socket与客户端id之间,形成映射关系(socket, id) 内存分配管理 一整块内存,不断分配小块 每分配一次,就加入到红黑 ...

  4. 《手把手教你》系列技巧篇(三十六)-java+ selenium自动化测试-单选和多选按钮操作-番外篇(详解教程)

    1.简介 前边几篇文章是宏哥自己在本地弄了一个单选和多选的demo,然后又找了网上相关联的例子给小伙伴或童鞋们演示了一下如何自动化测试,这一篇宏哥在网上找了一个问卷调查,给小伙伴或童鞋们来演示一下.上 ...

  5. 求1+2+3...+n 牛客网 剑指Offer

    求1+2+3...+n 牛客网 剑指Offer 题目描述 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). ...

  6. Python ValueError: Attempted relative import in non-package Relative import相对引用 错误

    包含相对路径import的python脚本不能直接运行,只能作为module被引用. 例如 from . import mod1 有这样代码的文件只能最为moulule为不能直接运行.相对路径就是相对 ...

  7. Python 类似 SyntaxError: Non-ASCII character '\xc3' in file

    Python 类似 SyntaxError: Non-ASCII character '\xc3' in file 产生这个问题的原因: python 的默认编码文件是ACSII,而编辑器将文件保存为 ...

  8. Tarjan算法离线 求 LCA(最近公共祖先)

    本文是网络资料整理或部分转载或部分原创,参考文章如下: https://www.cnblogs.com/JVxie/p/4854719.html http://blog.csdn.net/ywcpig ...

  9. JAVA笔记15__TCP服务端、客户端程序 / ECHO程序 /

    /** * TCP:传输控制协议,采用三方握手的方式,保证准确的连接操作. * UDP:数据报协议,发送数据报,例如:手机短信或者是QQ消息. */ /** * TCP服务器端程序 */ public ...

  10. 并发编程从零开始(十四)-Executors工具类

    并发编程从零开始(十四)-Executors工具类 12 Executors工具类 concurrent包提供了Executors工具类,利用它可以创建各种不同类型的线程池 12.1 四种对比 单线程 ...