Luogu P4709 信息传递 (群论、生成函数、多项式指数函数)
题意:
题解: 这道题我思路大方向是正确的,但是生成函数推错导致一直WA,看了标程才改对……
首先一个长为\(m\)的轮换的\(n\)次幂会分裂成\(\gcd(n,m)\)个长为\(\frac{m}{\gcd(n,m)}\)的轮换
所以合并的时候相当于对于一个长度\(l\)若存在一个\(m\)使得\(\frac{m}{\gcd(n,m)}=l\)则\(\gcd(n,m)\)个长度为\(l\)的轮换可以合并
显然不同长度的轮换是互不影响的,那么我们可以分开每种长度计算
就相当于对于一个长度为\(l\)的有标号的轮换,要把它们划分成若干无标号集合,每个集合大小都在给定的集合\(S\)内,并且每个集合有权值(合并的方案数),一种划分方案的权值为所有集合权值之积,求所有划分方案权值总和
那么显然这个东西的EGF就等于\(\exp(\sum_{i\in S} \frac{w_i}{i!})\), \(w_i\)为权值
如何求\(w_i\)? 在这里我出了问题
正确的答案是,假设\(k\)个长度为\(l\)的轮换合并,方案数为\(l^{k-1}(k-1)!\), 也就是\(\frac{l^kk!}{lk}\).
这大概是因为,假设我们定住第一个轮换的第一个元素的位置,那么其余每个轮换自身内部的顺序都可以改变,这样是\(l^{k-1}\)种;这些轮换之间的顺序也可以改变,这样是\((k-1)!\)种。
代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iostream>
#include<vector>
#define llong long long
using namespace std;
inline int read()
{
int x=0; bool f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
if(f) return x;
return -x;
}
const int N = 1<<19;
const int LGN = 19;
const int P = 998244353;
const int G = 3;
llong quickpow(llong x,llong y)
{
llong cur = x,ret = 1ll;
for(int i=0; y; i++)
{
if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}
cur = cur*cur%P;
}
return ret;
}
llong mulinv(llong x) {return quickpow(x,P-2);}
namespace FFT
{
llong tmp1[N+3],tmp2[N+3],tmp3[N+3],tmp4[N+3],tmp5[N+3],tmp6[N+3],tmp7[N+3],tmp8[N+3],tmp9[N+3],tmp10[N+3];
llong tst1[N+3],tst2[N+3],tst3[N+3];
llong sexp[N+3];
int fftid[N+3];
int getdgr(int n) {int ret = 1; while(ret<=n) ret<<=1; return ret;}
void init_fftid(int dgr)
{
int len = 0; for(int i=1; i<=LGN; i++) {if((1<<i)==dgr) {len = i; break;}}
fftid[0] = 0; for(int i=1; i<dgr; i++) fftid[i] = (fftid[i>>1]>>1)|((i&1)<<(len-1));
}
void ntt(int dgr,int coe,llong poly[],llong ret[])
{
init_fftid(dgr);
if(poly==ret) {for(int i=0; i<dgr; i++) {if(i<fftid[i]) swap(ret[i],ret[fftid[i]]);}}
else {for(int i=0; i<dgr; i++) ret[i] = poly[fftid[i]];}
for(int i=1; i<=(dgr>>1); i<<=1)
{
llong tmp = quickpow(G,(P-1)/(i<<1));
if(coe==-1) {tmp = mulinv(tmp);}
sexp[0] = 1ll; for(int j=1; j<i; j++) sexp[j] = sexp[j-1]*tmp%P;
for(int j=0; j<dgr; j+=(i<<1))
{
for(llong *k=ret+j,*kk=sexp; k<ret+i+j; k++,kk++)
{
llong y = k[i]*(*kk)%P;
k[i] = (*k)-y<0 ? (*k)-y+P : (*k)-y;
(*k) = (*k)+y>=P ? (*k)+y-P : (*k)+y;
}
}
}
if(coe==-1)
{
llong tmp = mulinv(dgr);
for(int i=0; i<dgr; i++) ret[i] = ret[i]*tmp%P;
}
}
void polymul(int dgr,llong poly1[],llong poly2[],llong ret[])
{
ntt((dgr<<1),1,poly1,tmp1); ntt((dgr<<1),1,poly2,tmp2);
for(int i=0; i<(dgr<<1); i++) ret[i] = tmp1[i]*tmp2[i]%P;
ntt((dgr<<1),-1,ret,ret);
}
void polyinv(int dgr,llong poly[],llong ret[])
{
for(int i=0; i<(dgr<<1); i++) ret[i] = tmp3[i] = tmp4[i] = tmp5[i] = 0ll;
ret[0] = mulinv(poly[0]);
for(int i=1; i<=(dgr>>1); i<<=1)
{
for(int j=0; j<(i<<1); j++) tmp3[j] = poly[j];
ntt((i<<2),1,tmp3,tmp4); ntt((i<<2),1,ret,tmp5);
for(int j=0; j<(i<<2); j++) tmp3[j] = tmp4[j]*tmp5[j]%P*tmp5[j]%P;
ntt((i<<2),-1,tmp3,tmp4);
for(int j=0; j<(i<<1); j++) ret[j] = (ret[j]+ret[j]-tmp4[j]+P)%P;
}
}
void polyder(int dgr,llong poly[],llong ret[])
{
for(int i=0; i<dgr-1; i++) ret[i] = poly[i+1]*(i+1)%P;
ret[dgr-1] = 0ll;
}
void polyint(int dgr,llong poly[],llong ret[])
{
for(int i=1; i<dgr; i++) ret[i] = poly[i-1]*mulinv(i)%P;
ret[0] = 0ll;
}
void polyln(int dgr,llong poly[],llong ret[])
{
for(int i=0; i<(dgr<<1); i++) ret[i] = tmp6[i] = tmp7[i] = tmp8[i] = 0ll;
polyder(dgr,poly,tmp6);
polyinv(dgr,poly,tmp7);
polymul(dgr,tmp6,tmp7,tmp8);
polyint(dgr,tmp8,ret);
}
void polyexp(int dgr,llong poly[],llong ret[])
{
for(int i=0; i<(dgr<<1); i++) ret[i] = tmp9[i] = tmp10[i] = 0ll;
ret[0] = 1ll;
for(int i=1; i<=(dgr>>1); i<<=1)
{
polyln((i<<1),ret,tmp9);
for(int j=0; j<(i<<1); j++) tmp9[j] = (-tmp9[j]+poly[j]+P)%P; tmp9[0]++;
polymul((i<<2),ret,tmp9,tmp10);
for(int j=0; j<(i<<1); j++) ret[j] = tmp10[j];
}
}
}
int permu[N+3];
int a[N+3];
int dgr[N+3];
bool vis[N+3];
vector<int> s[N+3];
llong f[N+3],expf[N+3];
llong fact[N+3];
int n;
int gcd(int x,int y) {return y==0?x:gcd(y,x%y);}
int main()
{
fact[0] = 1ll; for(int i=1; i<=N; i++) fact[i] = fact[i-1]*i%P;
scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d",&permu[i]);
for(int i=1; i<=n; i++)
{
if(vis[i]) continue;
int len = 1; vis[i] = true;
for(int j=permu[i]; j!=i; j=permu[j])
{
len++;
vis[j] = true;
}
a[len]++;
}
for(int i=1; i<=n; i++)
{
int g = gcd(i,n),l = i/gcd(i,n);
s[l].push_back(g);
}
llong ans = 1ll;
for(int i=1; i<=n; i++)
{
if(a[i]==0) continue;
int dgr = FFT::getdgr(a[i]);
for(int j=0; j<s[i].size(); j++)
{
if(s[i][j]<dgr)
{
f[s[i][j]] = (f[s[i][j]]+mulinv(s[i][j])*quickpow(i,s[i][j]-1))%P;
}
}
FFT::polyexp(dgr,f,expf);
ans = ans*expf[a[i]]%P*fact[a[i]]%P;
for(int j=0; j<(dgr<<1); j++) f[j] = expf[j] = 0ll;
}
printf("%lld\n",ans);
return 0;
}
Luogu P4709 信息传递 (群论、生成函数、多项式指数函数)的更多相关文章
- 【luogu P2661 信息传递】 题解
题目链接:https://www.luogu.org/problemnew/show/P2661#sub 一种利用并查集求最小环的做法: 对于每个同学看作一个点,每次信息传递是一条有向边,当出现最小环 ...
- luogu P2661 信息传递 x
P2661 信息传递 题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知 ...
- Luogu P2661 信息传递
传送门 一眼就能看出来是个并查集 但是并不会写... 看了一下题解说是并查集求最小环qwq 所以,每次加入第i个小同学,判断如果他要告诉的小同学k最后会告诉他(也就是转回来了), 就说明出现了一个环, ...
- 洛谷 P4709 - 信息传递(置换+dp)
题面传送门 一道挺有意思的题罢-- 首先看到这种与置换乘法相关的题,首先把这些置换拆成一个个置换环,假设输入的置换有 \(m\) 个置换环,大小分别为 \(s_1,s_2,\cdots,s_m\),显 ...
- 2015 NOIP day2 t2 信息传递 tarjan
信息传递 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.luogu.org/problem/show?pid=2661 Descrip ...
- Luogu2661 信息传递(图论)
Luogu2661 信息传递(图论) Description 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti ...
- 洛谷 P2661 信息传递(并查集 & 最小环)
嗯... 题目链接:https://www.luogu.org/problemnew/show/P2661 这道题和一些比较水的并查集不太一样,这道题的思路就是用并查集来求最小环... 首先,如果我们 ...
- 洛谷——P2661 信息传递
https://www.luogu.org/problem/show?pid=2661#sub 题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其 ...
- tg2015 信息传递 (洛谷p2661)
题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...
随机推荐
- CSS3面包屑菜单导航
在线演示 本地下载
- 附录3:RMA算法原理
RMA算法分三步: 一.背景校正(没精力写了) 二.归一化(没精力写了) 三.计算表达值 假设有5张芯片,这些芯片的某个探针组包含5个探针,它们的表达值如下: GeneChip 4 8 6 9 7 3 ...
- redis 学习(3)-- String 类型
redis 学习(3)-- String 类型 String-结构 结构:Key-Value对 Value:可以是字符串.数字,也可以是二进制数组 限制:Value最大值为512MB String-常 ...
- centos安装配置php
PHP的安装同样需要经过环境检查.编译和安装3个步骤. 1.首先用百度搜索 “PHP:Downloads”, 点击第一个网页: 选择5.5.37版本,选择 .tar.gz 格式的文件: 来到镜像列表网 ...
- linux入门到高级
目 录 1. Linux入门篇.................................................................................... ...
- docker 环境安装
centos7下安装docker.docker-compose 参考文档:https://docs.docker.com/ 一.安装docker 1).Docker 要求 CentOS 系统的内核版本 ...
- 在linux环境下安装oracle的问题记录
问题1 xhost:unable to open display 解决办法: 在linux虚拟机本机打开终端,执行 [root@bogon ~]# DISPLAY=:0.0;export DISPLA ...
- java7连接数据库 网页 添加学生信息测试
石家庄铁道大学2019年秋季 2018 级课堂测试试卷(六)(10分) 课程名称: JAVA语言程序设计 任课教师: 王建民 考试时间: 150 分钟 一. 考试要求: 1登录账号 ...
- 阿里云--安装nginx AND访问超时
首先先安装PCRE pcre-devel 和Zlib,因为配置nginx的时候会需要这两个东西PCRE(Perl Compatible Regular Expressions) 是一个Perl库,包括 ...
- sql练习03
准备数据建表语句CREATE TABLE students(sno VARCHAR(3) NOT NULL, sname VARCHAR(4) NOT NULL,ssex VARCHAR(2) NOT ...