别问我为啥突然刷了道OI题,也别问我为啥花括号不换行了...

题目描述

求含 \(n\) 个碳原子的本质不同的烷基数目模 \(998244353\) 的结果。\(1\le n\le 10^5\) 。


题解

Burnside引理+多项式牛顿迭代

不考虑同构的话,很容易想到dp方程 \(\begin{cases}f_0=1\\f_i=\sum\limits_{j+k+l+1=i}f_jf_kf_l\end{cases}\) 。

考虑同构,可以通过容斥原理,大力讨论一下容斥系数。一个更简单的方法是考虑Burnside引理,即:等价类的数目等于每个置换下不动点数目的平均值。

  • 对于置换 \((1,2,3)\) ,所有组合都是不动点;
  • 对于置换 \((1,3,2)\) 、\((2,1,3)\) 和 \((3,2,1)\) ,“\(2+1\)” 的组合是不动点;
  • 对于置换 \((2,3,1)\) 和 \((3,1,2)\) ,只有 “\(3\)” 的组合是不动点。

于是新的dp方程为 \(\begin{cases}f_0=1\\f_i=\frac{\sum\limits_{j+k+l+1=i}f_jf_kf_l+\sum\limits_{2j+k+1=i}3f_jf_k+\sum\limits_{3j+1=i}2f_j}6\end{cases}\) 。

\(n\) 这么大肯定不能直接dp,考虑多项式解法,则dp方程的多项式形式为 \(F(x)=x\cdot\frac{F^3(x)+3F(x)F(x^2)+2F(x^3)}6+1\) 。

由于出现了三次方和 \(F(x^2)\) 、\(F(x^3)\) 项,因此这个方程难以直接解出。

考虑牛顿迭代,则当我们已知 \(F(x)\mod x^n\) 时,\(F(x^2)\mod x^{2n}\) 和 \(F(x^3)\mod x^{2n}\) 就已经是已知量,在迭代时可以当作常量处理。

记 \(S(x)=F(x^2)\) ,\(C(x)=F(x^3)\) ,则我们要迭代的方程就是 \(G(T(x))=x\cdot\frac{T^3(x)+3S(x)T(x)+2C(x)}6-T(x)+1\) 的零点 \(G(F(x))=0\) 。

又因为 \(G'(T(x))=x\cdot\frac{3T^2(x)+3S(x)}6-1\) ,代入牛顿迭代公式 \(F(x)=F_0(x)-\frac{G(F_0(x))}{G'(F_0(x))}\) 中可得

\[F(x)=F_0(x)-\frac{x(F_0^3(x)+3S(x)F_0(x)+2C(x))-6F_0(x)+6}{3F_0^2(x)+3S(x)-6},
\]

其中 \(F_0(x)\) 是上次迭代所得的多项式。

最后的答案就是 \(F(x)[n]\) 。

时间复杂度 \(O(n\log n)\) 。

#include <cstdio>
#include <algorithm>
#define N 262155
#define mod 998244353
using namespace std;
typedef long long ll;
ll F[N];
inline ll qpow(ll x , ll y) {
ll ans = 1;
while(y) {
if(y & 1) ans = ans * x % mod;
x = x * x % mod , y >>= 1;
}
return ans;
}
inline void ntt(ll *A , int n , ll flag) {
int i , j , k;
for(k = i = 0 ; i < n ; i ++ ) {
if(i < k) swap(A[i] , A[k]);
for(j = (n >> 1) ; (k ^= j) < j ; j >>= 1);
}
for(k = 2 ; k <= n ; k <<= 1) {
ll wn = qpow(3 , (mod - 1) / k * flag);
for(i = 0 ; i < n ; i += k) {
ll w = 1 , t;
for(j = i ; j < i + (k >> 1) ; j ++ , w = w * wn % mod)
t = w * A[j + (k >> 1)] % mod , A[j + (k >> 1)] = (A[j] - t + mod) % mod , A[j] = (A[j] + t) % mod;
}
}
if(flag == mod - 2) {
ll t = qpow(n , flag);
for(i = 0 ; i < n ; i ++ ) A[i] = A[i] * t % mod;
}
}
inline void inv(ll *A , ll *B , int n) {
static ll T[N];
int i , j;
for(i = 0 ; i < (n << 1) ; i ++ ) B[i] = 0;
B[0] = qpow(A[0] , mod - 2);
for(i = 2 ; i <= n ; i <<= 1) {
for(j = 0 ; j < i ; j ++ ) T[j] = A[j] , T[j + i] = 0;
ntt(T , i << 1 , 1) , ntt(B , i << 1 , 1);
for(j = 0 ; j < (i << 1) ; j ++ ) B[j] = B[j] * (2 - T[j] * B[j] % mod + mod) % mod;
ntt(B , i << 1 , mod - 2);
for(j = i ; j < (i << 1) ; j ++ ) B[j] = 0;
}
}
inline void solve(int n) {
static ll G[N] , H[N] , S[N] , C[N] , T[N];
int i , j;
F[0] = 1;
for(i = 2 ; i <= n ; i <<= 1) {
for(j = 0 ; j < i ; j ++ ) T[j] = F[j] , S[j] = C[j] = T[j + i] = S[j + i] = C[j + i] = 0;
for(j = 0 ; j < i ; j += 2) S[j] = F[j / 2];
for(j = 0 ; j < i ; j += 3) C[j] = F[j / 3];
ntt(T , i << 1 , 1) , ntt(S , i << 1 , 1);
for(j = 0 ; j < (i << 1) ; j ++ ) G[j] = T[j] * (T[j] * T[j] % mod + 3 * S[j]) % mod , H[j] = 3 * (T[j] * T[j] + S[j]) % mod;
ntt(G , i << 1 , mod - 2) , ntt(H , i << 1 , mod - 2);
for(j = i ; j < (i << 1) ; j ++ ) G[j] = H[j] = 0;
for(j = i - 1 ; j ; j -- ) G[j] = ((G[j - 1] + 2 * C[j - 1] - 6 * F[j]) % mod + mod) % mod , H[j] = H[j - 1];
G[0] = 0 , H[0] = mod - 6;
ntt(G , i << 1 , 1) , inv(H , T , i) , ntt(T , i << 1 , 1);
for(j = 0 ; j < (i << 1) ; j ++ ) G[j] = G[j] * T[j] % mod;
ntt(G , i << 1 , mod - 2);
for(j = 0 ; j < i ; j ++ ) F[j] = (F[j] - G[j] + mod) % mod;
}
}
int main() {
int n , len = 1;
scanf("%d" , &n);
while(len <= n) len <<= 1;
solve(len);
printf("%lld\n" , F[n]);
return 0;
}

【loj6538】烷基计数 加强版 加强版 Burnside引理+多项式牛顿迭代的更多相关文章

  1. LOJ #6538. 烷基计数 加强版 加强版(生成函数,burnside引理,多项式牛顿迭代)

    传送门. 不妨设\(A(x)\)表示答案. 对于一个点,考虑它的三个子节点,直接卷起来是\(A(x)^3\),但是这样肯定会计重,因为我们要的是无序的子节点. 那么用burnside引理,枚举一个排列 ...

  2. Luogu P5564 [Celeste-B]Say Goodbye (多项式、FFT、Burnside引理、组合计数)

    题目链接 https://www.luogu.org/problem/P5564 题解 这题最重要的一步是读明白题. 为了方便起见下面设环长可以是\(1\), 最后统计答案时去掉即可. 实际上就相当于 ...

  3. 【等价的穿越】Burnside引理&Pólya计数法

    Problem 起源: SGU 294 He's Circle 遗憾的是,被吃了. Poj有道类似的: Mission 一个长度为n(1≤n≤24)的环由0,1,2组成,求有多少本质不同的环. 实际上 ...

  4. 等价类计数:Burnside引理 & Polya定理

    提示: 本文并非严谨的数学分析,有很多地方是自己瞎口胡的,仅供参考.有错误请不吝指出 :p 1. 群 1.1 群的概念 群 \((S,\circ)\) 是一个元素集合 \(S\) 和一种二元运算 $ ...

  5. 等价类计数(Polya定理/Burnside引理)学习笔记

    参考:刘汝佳<算法竞赛入门经典训练指南> 感觉是非常远古的东西了,几乎从来没有看到过需要用这个的题,还是学一发以防翻车. 置换:排列的一一映射.置换乘法相当于函数复合.满足结合律,不满足交 ...

  6. BZOJ 1488 Luogu P4727 [HNOI2009]图的同构 (Burnside引理、组合计数)

    题目链接 (Luogu) https://www.luogu.org/problem/P4727 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.ph ...

  7. BZOJ_[HNOI2008]_Cards_(置换+Burnside引理+乘法逆元+费马小定理+快速幂)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1004 共n个卡片,染成r,b,g三种颜色,每种颜色的个数有规定.给出一些置换,可以由置换得到的 ...

  8. 置换群 Burnside引理 Pólya定理(Polya)

    置换群 设\(N\)表示组合方案集合.如用两种颜色染四个格子,则\(N=\{\{0,0,0,0\},\{0,0,0,1\},\{0,0,1,0\},...,\{1,1,1,1\}\}\),\(|N|= ...

  9. burnside引理&polya定理

    burnside引理&polya定理 参考资料: <polya计数法的应用>--陈瑜希 黄学长 置换: 置换即是将n个元素的染色进行交换,产生一个新的染色方案. 群: 一个元素的集 ...

随机推荐

  1. HDU5036(bitset加速传递闭包+期望)

    HDU5036 题解 题目链接 思路: 求出破坏or打开所有门所需要的期望炮弹数量,那么根据期望的线性性质,我们可以求出每一个门的期望值最后累加起来就行了. 我们最后的目标就是求对于一个门\(i\), ...

  2. 洛谷 P3071 [USACO13JAN]座位Seating(线段树)

    P3071 [USACO13JAN]座位Seating 题目链接 思路: 一开始把题给读错了浪费了好多时间呜呜呜. 因为第二个撤离操作是区间修改,所以我们可以想到用线段树来做.对于第一个操作,我们只需 ...

  3. 后端将Long类型数据传输到前端出现精度丢失的问题

    当将超过16位的数字传输到前端的时候,就会出现精度丢失的问题,然后我按照网上的几种方法实验的时候,只有一种方法成功了.可能是因为环境等方面的问题. 我这里成功是因为:最后使用的是配置mvc的方式,然后 ...

  4. reactNative 获取组件高、宽、位置等信息

    import {findNodeHandle, UIManager} from 'react-native' layout(ref) { const handle = findNodeHandle(r ...

  5. pmm 添加proxysql metrics

    pmm 对于proxysql 的管理是基于metrics的进行处理的,使用的是proxysql exporter 对于proxysql exporter的添加,比较简单,我们可以通过独立的额容器运行e ...

  6. luoguP3374 【模板】树状数组 1 cdq

    链接 luogu 思路 可耐我连cdq都不会,Orz 陈丹琦 代码 #include <bits/stdc++.h> using namespace std; const int N = ...

  7. javaScript之DOM,BOM

    javaScript之BOM / DOM: BOM(Browser Object Model)是指浏览器对象模型,它使 JavaScript 有能力与浏览器进行"对话". DOM ...

  8. UE4的多线程

    1. 源代码 AsyncWork.h 2. 多线程的使用 参考文档:https://wiki.unrealengine.com/Using_AsyncTasks 当我们需要执行一个需要很长时间的任务时 ...

  9. 前端微服务初试(singleSpa)

    1.基本概念 实现一套微前端架构,可以把其分成四部分(参考:https://alili.tech/archive/11052bf4/) 加载器:也就是微前端架构的核心,主要用来调度子应用,决定何时展示 ...

  10. plsql excel导入报错:未发现数据源名称并且未指定默认驱动程序

        1.情景展示 使用plsql的odbc导入器,导入excel数据时,报错信息如下: anydac 未发现数据源名称如何处理 2.原因分析 操作系统的问题,我的是64位的系统,plsql支持32 ...