luoguP4709 信息传递 置换 + 多项式exp

感觉我的做法并不是最优做法...
考虑一个置换\(g\)中的一个置换环\(S\)
在\(g^n\)的形态中,它变为了\(gcd(n, |S|)\)个长度相同的置换环
那么,我们考虑对\(f\)的所有置换环考虑
所有的长度相同的置换环都可以合并
如果\(a\)个长度为\(b\)的置换环合并成一个环,那么方案数为\(b^{a - 1} (a - 1)!\)
需要判掉不合法的情况
其意义是考虑第一个置换以及固定第一个元素,其他任意选择
以这个弄出指数生成函数\(F(x)\),那么对于长度为\(b\)的合并方案就是\(e^{F(x)} [num(b)]\)\
对于每个长度都这么讨论即可
复杂度\(O(n \log n)\)
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define ri register int
#define rec(io, ed) for(ri io = 0; io < ed; io ++)
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
#define drep(io, ed, st) for(ri io = ed; io >= st; io --)
#define gc getchar
inline int read() {
int p = 0, w = 1; char c = gc();
while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
return p * w;
}
const int sid = 3e5 + 5;
const int mod = 998244353;
inline void inc(int &a, int b) { a += b; if(a >= mod) a -= mod; }
inline void dec(int &a, int b) { a -= b; if(a < 0) a += mod; }
inline int mul(int a, int b) { return 1ll * a * b % mod; }
inline int fp(int a, int k) {
int ret = 1;
for( ; k; k >>= 1, a = mul(a, a))
if(k & 1) ret = mul(ret, a);
return ret;
}
int n, rev[sid];
int vis[sid], nc[sid], p[sid];
inline void init(int Mn, int &N, int &lg) {
N = 1, lg = 0;
while(N < Mn) N <<= 1, lg ++;
}
inline void NTT(int *a, int n, int opt) {
rec(i, n) if(i < rev[i]) swap(a[i], a[rev[i]]);
for(ri i = 1; i < n; i <<= 1)
for(ri j = 0, g = fp(3, (mod - 1) / (i << 1)); j < n; j += (i << 1))
for(ri k = j, G = 1; k < i + j; k ++, G = mul(G, g)) {
int x = a[k], y = mul(G, a[i + k]);
a[k] = (x + y >= mod) ? x + y - mod : x + y;
a[i + k] = (x - y <0) ? x - y + mod : x - y;
}
if(opt == -1) {
reverse(a + 1, a + n);
int ivn = fp(n, mod - 2);
rec(i, n) a[i] = mul(a[i], ivn);
}
}
int iva[sid], ivb[sid];
inline void Inv(int *a, int *b, int n) {
if(n == 1) { b[0] = fp(a[0], mod - 2); return; }
Inv(a, b, n >> 1);
int N = 1, lg = 0; init(n + n, N, lg);
rec(i, N) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
rec(i, N) iva[i] = ivb[i] = 0;
rec(i, n) iva[i] = a[i], ivb[i] = b[i];
NTT(iva, N, 1); NTT(ivb, N, 1);
rec(i, N) iva[i] = ((ivb[i] << 1) % mod - mul(iva[i], mul(ivb[i], ivb[i])) + mod) % mod;
NTT(iva, N, -1);
rec(i, n) b[i] = iva[i];
}
int inv[sid], ivf[sid], fac[sid];
inline void pre() {
inv[0] = inv[1] = 1;
fac[0] = fac[1] = 1;
rep(i, 2, 200000) fac[i] = mul(fac[i - 1], i);
rep(i, 2, 200000) inv[i] = mul(inv[mod % i], mod - mod / i);
rep(i, 0, 200000) ivf[i] = fp(fac[i], mod - 2);
}
inline void wf(int *a, int *b, int n) { for(ri i = 1; i < n; i ++) b[i - 1] = mul(a[i], i); }
inline void jf(int *a, int *b, int n) { for(ri i = 1; i < n; i ++) b[i] = mul(a[i - 1], inv[i]); }
int ina[sid], inb[sid];
inline void In(int *a, int *b, int n) {
int N = 1, lg = 0; init(n + n, N, lg);
rec(i, N) ina[i] = inb[i] = 0;
wf(a, ina, n); Inv(a, inb, n);
rec(i, N) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
NTT(ina, N, 1); NTT(inb, N, 1);
rec(i, N) ina[i] = mul(ina[i], inb[i]);
NTT(ina, N, -1); jf(ina, b, n);
}
int exa[sid], exb[sid];
inline void Exp(int *a, int *b, int n) {
if(n == 1) { b[0] = 1; return; }
Exp(a, b, n >> 1);
rec(i, n + n) exb[i] = exa[i] = 0;
In(b, exb, n);
int N = 1, lg = 0; init(n + n, N, lg);
rec(i, N) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
rec(i, n) exa[i] = b[i], exb[i] = (a[i] - exb[i] + mod) % mod; exb[0] ++;
NTT(exa, N, 1); NTT(exb, N, 1);
rec(i, N) exa[i] = mul(exa[i], exb[i]);
NTT(exa, N, -1);
rec(i, n) b[i] = exa[i];
}
inline int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int f[sid], g[sid];
inline void wish() {
rep(i, 1, n) {
if(vis[i]) continue;
int L = 0;
for(ri t = i; !vis[t]; t = p[t]) vis[t] = 1, L ++;
nc[L] ++;
}
pre();
int ret = 1;
rep(i, 1, n) if(nc[i]) {
int v = nc[i];
rep(j, 0, v) f[j] = g[j] = 0;
rep(j, 0, v) {
if(gcd(j * i, n) != j) continue;
f[j] = mul(mul(fac[j - 1], fp(i, j - 1)), ivf[j]);
}
int N = 1;
while(N < v + 5) N <<= 1;
Exp(f, g, N);
ret = mul(ret, mul(g[v], fac[v]));
}
printf("%d\n", ret);
}
int main() {
n = read();
rep(i, 1, n) p[i] = read();
wish();
return 0;
}
luoguP4709 信息传递 置换 + 多项式exp的更多相关文章
- 洛谷 - Sdchr 的邀请赛 T4 信息传递
(乱搞艹爆正解系列) 对不起,由于博主太弱了,并不会正解的多项式exp(甚至多项式exp我都不会2333). 只能来说一说我是怎么乱搞的啦QWQ 首先这个题最关键的性质是: 一个在原置换 g 中长度为 ...
- tg2015 信息传递 (洛谷p2661)
题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...
- [NOIP2015]信息传递
[NOIP2015]信息传递[问题描述]有
- [NOIP2015] 提高组 洛谷P2661 信息传递
题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...
- 使用postMesssage()实现跨域iframe页面间的信息传递----转载
由于web同源策略的限制,当页面使用跨域iframe链接时,主页面与子页面是无法交互的,这对页面间的信息传递造成了不小的麻烦,经过一系列的尝试,最后我发现有以下方法可以实现: 1. 子页面url传参 ...
- 洛谷 P2661 信息传递 Label:并查集||强联通分量
题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...
- NOIP 2015 信息传递
kawayi 题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的 ...
- AC日记——信息传递 洛谷 P2661 (tarjan求环)
题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...
- 2015 NOIP day2 t2 信息传递 tarjan
信息传递 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.luogu.org/problem/show?pid=2661 Descrip ...
随机推荐
- Python学习之not,and,or篇
Python学习之not,and,or篇 运算符示意 not –表示取反运算. and –表示取与运算. or –表示取或运算. 运算符优先级 not > and > or. 举例如下: ...
- C++ virtual函数重写,在继承的时候没有在函数前写virtual关键字也依然是虚函数吗?
比如: class Base { Base() {}; ~Base() {}; virtual void Init(); }; class Derived:public Base { virtual ...
- root权限使用vim不能修改权限
1.背景: 有时候我们会发现使用root权限不能修改某个文件,大部分原因是曾经使用chattr将文件锁定了 2.chattr命令介绍: 用来改变文件属性,能防止root用户误删文件等作用 3.使用方法 ...
- Android数据存储:Shared Preferences
Android数据存储之SharedPreferences 在Android系统中提供了多种存储技术.通过这些存储技术可以将数据存储在各种存储介质上, Android 为数据存储提供了如下几种方式:1 ...
- [学习笔记]JS 数组Array push相关问题
前言: 今天用写了一个二维数组,都赋值为零,然后更新其中一个值,结果和预期是不一样,会整列的相同位置都是同一个值. 1.用Chrome的控制台样例如下: arrs[2][2] =1的赋值,竟然是三个数 ...
- spoj227 树状数组插队序列问题
插队问题和线段树解决的方式一样,每个结点维护值的信息是该节点之前的空位有多少,然后从后往前插点即可 注意该题要求输出的是从左往右输出每个士兵的等级,即问士兵最后排在第几个位置 /* 树状数组维护前i个 ...
- unittest中更高效的执行测试用例一个类只需要打开一次浏览器
示例代码 baidu.py # _*_ coding:utf-8 _*_ import csv,unittest #导入csv模块 from time import sleep from seleni ...
- 步步为营-64-进程&线程
1 进程 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; us ...
- 2017-2018-2 20155309南皓芯 Exp6 信息搜集与漏洞扫描
实践内容 1.各种搜索技巧的应用 2.DNS IP注册信息的查询 3.基本的扫描技术:主机发现.端口扫描.OS及服务版本探测.具体服务的查点 4.漏洞扫描:会扫,会看报告,会查漏洞说明,会修补漏洞 基 ...
- 《剑指offer》-青蛙跳台阶II
一只青蛙一次可以跳上1级台阶,也可以跳上2级--它也可以跳上n级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 其实题目很水...就是一个等比数列通项公式嘛 f(0)=1 f(1)=1 f(n)=f( ...