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同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...
随机推荐
- 客户端相关知识学习(三)之Android原生与H5交互的实现
Android原生与H5交互的实现 H5调用原生的方式 方式可能有多种,根据开发经验,接触过两种方式. 方法一:Android向H5注入全局js对象,也就是H5调Android 1.首先对WebVie ...
- 机器学习-SVM-手写识别问题
机器学习-SVM-手写识别问题 这里我们解决的还是之前用KNN曾经解决过的手写识别问题(https://www.cnblogs.com/jiading/p/11622019.html),但相比于KNN ...
- JDBC2
1.JDBC连接池 public class JdbcTemplateDemo2 { //Junit单元测试,可以让方法独立执行 //1. 获取JDBCTemplate对象 private JdbcT ...
- VUE 从零开始 学习笔记 一
最近刚跳到一个新公司 不是很忙 决定系统的学习一下VUE这个前端框架 参考官方API 好了 废话不多说 开始了 首先 说一下吧 现在很火的主流三大前端框架 Vue,Angular.React, 为什么 ...
- 无线传输模块HC-12
无线传输模块HC-12使用 因为实验室的无人机需要使用一款无线传输模块进行遥控控制,我们讨论的中测试了HC-12,并对HC-12传输距离进行了简单测试.在此做下使用记录. 模块概述 HC-12 无线串 ...
- nginx学习第三章
一.系统环境 ubuntu6.4系统 nginx 版本: nginx/1.10.3 (Ubuntu). 二.打开目录浏览功能Nginx默认是不允许列出整个目录的.如需此功能,编辑虚拟主机配置文件,在l ...
- 《Python基础教程》一点笔记
这本书还是月初的时候翻了翻,看了前十章左右就发现这本书写的比较烂,翻译地就更烂了,讲的内容其实没有抓住重点. 下面是看的时候记得几小段代码: #首字母相同的男生女生 girls = ['alice', ...
- @InitBinder的作用
由@InitBinder表示的方法,可以对WebDataBinder对象进行初始化.WebDataBinder是DataBinder的子类,用于完成由表单到JavaBean属性的绑定. @InitBi ...
- Spring源代码下载和导入eclipse
下载源代码包并解压,我下载的是3.2版本,下载地址在https://github.com/spring-projects/spring-framework/tree/3.2.x 因为Spring是使用 ...
- 组件(2):使用Prop下发数据
数据下发 组件实例的作用域是相互独立的,父.子组件之间无法进行数据的共享.如果想在子组件模板中使用父组件的数据,可以通过Prop将父组件的数据下发到子组件.子组件用props选项声明它预期的数据. 为 ...