洛谷 P4709 - 信息传递(置换+dp)
一道挺有意思的题罢……
首先看到这种与置换乘法相关的题,首先把这些置换拆成一个个置换环,假设输入的置换有 \(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)的更多相关文章
- 洛谷P2661 信息传递(最小环,并查集)
洛谷P2661 信息传递 最小环求解采用并查集求最小环. 只适用于本题的情况.对于新加可以使得两个子树合并的边,总有其中一点为其中一棵子树的根. 复杂度 \(O(n)\) . #include< ...
- [NOIP2015] 提高组 洛谷P2661 信息传递
题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...
- 洛谷 P2661 信息传递 Label:并查集||强联通分量
题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...
- 洛谷P2661 信息传递==coedevs4511 信息传递 NOIP2015 day1 T2
P2661 信息传递 题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知 ...
- 洛谷 P2661 信息传递(并查集 & 最小环)
嗯... 题目链接:https://www.luogu.org/problemnew/show/P2661 这道题和一些比较水的并查集不太一样,这道题的思路就是用并查集来求最小环... 首先,如果我们 ...
- NOIP2015提高组T2 洛谷P2661 信息传递
题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...
- 洛谷——P2661 信息传递
https://www.luogu.org/problem/show?pid=2661#sub 题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其 ...
- 洛谷 P2661 信息传递 题解
P2661 信息传递 题目描述 有 \(n\) 个同学(编号为 \(1\) 到 \(n\) )正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为 \(i\) 的同学的信息传 ...
- 洛谷p2661信息传递题解
题目 这个题一眼看上去就是用并查集求最小环. 我们可以设两个数组分别是f,d分别表示该点的爸爸和该点到祖先的距离. 当该点的爸爸等于他时,那他肯定就是祖先. 此时信息就肯定传递完了,此时的整个图中(我 ...
随机推荐
- 封装一个的toast弹出框(vue项目)
逆风的方向,更适合飞翔 实现效果 实现步骤 先写出一个toast组件 // Toast.vue <template> <div id="toast" :class ...
- 改善深层神经网络-week1编程题(Regularization)
Regularization Deep Learning models have so much flexibility and capacity that overfitting can be a ...
- HttpClient使用GET方式通过代理服务器读取页面的例子
import java.io.BufferedReader;import java.io.InputStreamReader;import org.apache.http.HttpEntity;imp ...
- Scrum Meeting 0529
零.说明 日期:2021-5-29 任务:简要汇报七日内已完成任务,计划后两日完成任务 一.进度情况 组员 负责 七日内已完成的任务 后两日计划完成的任务 困难 qsy PM&前端 完成后端管 ...
- UltraSoft - Beta - Scrum Meeting 2
Date: May 18th, 2020. Scrum 情况汇报 进度情况 组员 负责 今日进度 q2l PM.后端 建立Beta仓库管理增加服务器部署和Git协作文档 Liuzh 前端 查阅响应式布 ...
- SpringBoot加密配置属性
一.背景 在系统中的运行过程中,存在很多的配置属性,比如: 数据库配置.阿里云配置 等等,这些配置有些属性是比较敏感的,是不应直接以明文的方式出现在配置文件中,因此对于这些配置我们就需要加密来处理. ...
- 【Azure 应用服务】App Service For Linux 部署Java Spring Boot应用后,查看日志文件时的疑惑
编写Java Spring Boot应用,通过配置logging.path路径把日志输出在指定的文件夹中. 第一步:通过VS Code创建一个空的Spring Boot项目 第二步:在applicat ...
- 『学了就忘』Linux基础 — 10、VMware虚拟机中克隆的使用
目录 1.什么是克隆 2.克隆的两种类型 (1)完整克隆 (2)链接克隆 3.克隆操作 步骤一:克隆虚拟机 步骤二:进行克隆导向 3.快照与克隆的区别 4.镜像的管理 快照和克隆是VMware中两个非 ...
- Ubuntu鼠标变十字 不能点击
出现这种情况,应该是bash 直接运行了python文件 系统中出现了一个import 进程. python文件中除了注释应该是import在最前边 ps -ef|grep import 可以查看系统 ...
- 重建二叉树 牛客网 剑指Offer
重建二叉树 牛客网 剑指Offer 题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3, ...