Solution -「JZOJ #5457」项链
\(\mathscr{Description}\)
给定一条有 \(n\) 个点的圆环和 \(m\) 中颜色, 求在位置旋转, 位置翻转, 颜色旋转等价的意义下, 本质不同的染色方案数.
数据组数 \(T\le20\), \(n,m\le10^{18}\).
\(\mathscr{Solution}\)
颜色旋转 ... 那么它就不是颜色了, 就用 Burnside 就行.
首先需要明确的是, 我们的变换群长什么样子. 以 \(n=4,m=3\) 的情况为例:
G &= (\{
\iota_4,
\begin{pmatrix}4&1&2&3\end{pmatrix},
\begin{pmatrix}3&4&1&2\end{pmatrix},
\begin{pmatrix}2&3&4&1\end{pmatrix}
\} \\ &\cup\{
\iota_4,
\begin{pmatrix}2&1&4&3\end{pmatrix},
\begin{pmatrix}3&2&1&4\end{pmatrix},
\begin{pmatrix}4&3&1&2\end{pmatrix}
\})\\
&\times \{
\iota_3,
\begin{pmatrix}3&1&2\end{pmatrix},
\begin{pmatrix}2&3&1\end{pmatrix}
\}.
\end{aligned}
\]
第一组是位置旋转, 第二组是位置对称翻转, 第三组是颜色旋转, \(\times\) 是笛卡尔积.
Burnside, 考虑不动点. 假设某个 (位置, 颜色) 的映射对为 \((\varphi_p,\varphi_c)\), 位置 \(x\) 的颜色为 \(c(x)\), 那么不动点需要满足 \(\varphi_c(c(x))=c(\varphi_p(x))\). 先来研究 \(\varphi_p\) 是旋转置换的情况. 通过一些形象的观察可以发现, 设 \(\varphi_p\) 的轮换大小为 \(l_1\), \(\varphi_c\) 的轮换大小为 \(l_2\), 则不动点存在当且仅当 \(l_2\mid l_1\). 此时对于 \(\varphi_p\) 的一个环, 只要确定其中一个位置的颜色, 就可以根据 \(\varphi_c(c(x))=c(\varphi_p(x))\) 唯一确定环上其他点的颜色, 此时环的方案数为 \(m\).
因此, 枚举 \(l_1,l_2\), 我们可以得到 \(\varphi_p\) 是旋转置换时的不动点总数 (式子里的 \(\varphi\) 是欧拉函数 w):
\textit{ans}_1 &= \sum_{l_1\mid n}\varphi(l_1)\sum_{l_2\mid m,l_2\mid l_1}\varphi(l_2)m^{n/l_1}\\
&= \sum_{l_1\mid n}\varphi(l_1)m^{n/l_1}\gcd(m,l_1).
\end{aligned}
\]
此后, 对于对称置换的 \(\textit{ans}_2\), 需要讨论一下奇偶性:
- \(2\nmid n\), 此时所有置换的都有一个 \(l_1=1\) 的轮换, 因此 \(l_2=1\). 总不动点数为 \(n\cdot m^{(n+1)/2}\).
- \(2\mid n,2\nmid m\), 当对称轴放在两个点上时, 和前一种一样, 总不动点数为 \(n/2\cdot m^{n/2+1}\); 当对称轴放在两对点中间时, 所有 \(l_2=2\), 但是 \(2\nmid m\), 所以还是有 \(l_2=1\), 总不动点数为 \(n/2\cdot m^{n/2}\).
- \(2\mid n,2\mid m\), 当对称轴放在两个点上时还是 \(n/2\cdot m^{n/2+1}\); 当对称轴放在两对点中间时, \(l_2\) 可以取 \(1\) 或 \(2\), 总不动点数为 \(n/2\cdot m^{n/2}+n/2\cdot m^{n/2}\).
置换群大小为 \(2nm\), 所以答案为 \((\textit{ans}_1+\textit{ans}_2)/(2nm)\). 计算上需要 Pollard-Rho, 精细处理 \(\gcd\), 顺便预处理 \(m\) 的光速幂, 可以做到 \(\mathcal O(d(n))\).
\(\mathscr{Code}\)
/*+Rainybunny+*/
// #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)
typedef long long LL;
typedef std::unordered_map<LL, int> MType;
typedef MType::iterator IType;
#define fi first
#define se second
const int MOD = 998244353;
int ans;
LL n, m;
namespace Factor {
inline LL add(LL u, const LL v, const LL m) {
return (u += v) < m ? u : u - m;
}
inline LL mul(const LL u, const LL v, const LL m) {
return __int128(u) * v % m;
}
inline LL mpow(LL u, LL v, LL m) {
LL ret = 1;
for (; v; u = mul(u, u, m), v >>= 1) ret = mul(ret, v & 1 ? u : 1, m);
return ret;
}
inline LL gcd(const LL u, const LL v) { return v ? gcd(v, u % v) : u; }
inline LL labs(const LL u) { return u < 0 ? -u : u; }
inline bool millerRabin(const LL x, const LL b) {
LL k = x - 1; while (!(k & 1)) k >>= 1;
static LL pwr[70]; pwr[0] = 1, pwr[1] = mpow(b, k, x);
while (k != x - 1) {
pwr[pwr[0] + 1] = mul(pwr[pwr[0]], pwr[pwr[0]], x);
++pwr[0], k <<= 1;
}
per (i, pwr[0], 1) {
if (pwr[i] != 1 && pwr[i] != x - 1) return false;
if (pwr[i] == x - 1) return true;
}
return true;
}
inline bool isprime(const LL x) {
if (x == 2 || x == 3 || x == 5 || x == 7 || x == 11) return true;
if (x == 61 || x == 127) return true;
if (!(x % 2) || !(x % 3) || !(x % 5) || !(x % 7) || !(x % 11))return false;
if (!(x % 61) || !(x % 127)) return false;
return millerRabin(x, 2) && millerRabin(x, 61) && millerRabin(x, 127);
}
inline LL pollardRho(const LL x) {
static std::mt19937 emt(time(0) ^ 20120712);
for (LL a = emt() % (x - 1) + 1, len = 1, st = 0, ed = 0; ;
len <<= 1, st = ed) {
LL prd = 1;
rep (stp, 1, len) {
prd = mul(prd, labs(st - (ed = add(mul(ed, ed, x), a, x))), x);
if (!(stp & 127) && gcd(prd, x) > 1) return gcd(prd, x);
}
if (gcd(prd, x) > 1) return gcd(prd, x);
}
}
inline void factor(LL x, MType& res, const int k = 1) {
if (x == 1) return ;
if (isprime(x)) return void(res[x] += k);
LL d = pollardRho(x); int cnt = 0;
while (!(x % d)) x /= d, ++cnt;
factor(x, res, k), factor(d, res, k * cnt);
}
} // namespace Factor
inline int mul(const int u, const int v) { return 1ll * u * v % MOD; }
inline void subeq(int& u, const int v) { (u -= v) < 0 && (u += MOD); }
inline int sub(int u, const int v) { return (u -= v) < 0 ? u + MOD : u; }
inline void addeq(int& u, const int v) { (u += v) >= MOD && (u -= MOD); }
inline int add(int u, const int v) { return (u += v) < MOD ? u : u - MOD; }
inline int mpow(int u, int v) {
int ret = 1;
for (; v; u = mul(u, u), v >>= 1) ret = mul(ret, v & 1 ? u : 1);
return ret;
}
MType buc;
inline int solve(const IType it, const int phi, const LL l) {
if (it == buc.end()) {
return mul(mul(phi, std::__gcd(m, l) % MOD),
mpow(m % MOD, n / l % (MOD - 1)));
}
int ret = 0, tp = phi; LL tl = l;
IType tmp(std::next(it));
rep (i, 0, it->se) {
addeq(ret, solve(tmp, tp, tl));
tp = mul(tp, (it->fi - !i) % MOD), tl *= it->fi;
}
return ret;
}
int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%lld %lld", &n, &m), ans = 0;
if (n & 1) {
addeq(ans, mul(n % MOD, mpow(m % MOD, (n + 1 >> 1) % (MOD - 1))));
} else {
addeq(ans, mul((n >> 1) % MOD,
mpow(m % MOD, (n >> 1) % (MOD - 1))));
addeq(ans, mul((n >> 1) % MOD,
mpow(m % MOD, (n / 2 + 1) % (MOD - 1))));
if (~m & 1) {
addeq(ans, mul((n >> 1) % MOD,
mpow(m % MOD, (n >> 1) % (MOD - 1))));
}
}
buc.clear();
Factor::factor(n, buc);
addeq(ans, solve(buc.begin(), 1, 1));
ans = mul(ans, mpow(mul(m % MOD, (n << 1) % MOD), MOD - 2));
printf("%d\n", ans);
}
return 0;
}
Solution -「JZOJ #5457」项链的更多相关文章
- Solution -「ARC 104E」Random LIS
\(\mathcal{Description}\) Link. 给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...
- Solution -「CTS 2019」「洛谷 P5404」氪金手游
\(\mathcal{Description}\) Link. 有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ...
- Solution -「BZOJ 3812」主旋律
\(\mathcal{Description}\) Link. 给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...
- Solution -「CF 1342E」Placing Rooks
\(\mathcal{Description}\) Link. 在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ...
- Solution -「简单 DP」zxy 讲课记实
魔法题位面级乱杀. 「JOISC 2020 Day4」治疗计划 因为是不太聪明的 Joker,我就从头开始理思路了.中途也会说一些和 DP 算法本身有关的杂谈,给自己的冗长题解找借口. 首先,治疗方案 ...
- Solution -「基环树」做题记录
写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...
- Solution -「WC 2022」秃子酋长
\(\mathscr{Description}\) Link. (It's empty temporarily.) 给定排列 \(\{a_n\}\),\(q\) 次询问,每次给出 \([l,r ...
- Solution -「JSOI 2019」「洛谷 P5334」节日庆典
\(\mathscr{Description}\) Link. 给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的). \(|S|\le3\time ...
- Solution -「CF 1622F」Quadratic Set
\(\mathscr{Description}\) Link. 求 \(S\subseteq\{1,2,\dots,n\}\),使得 \(\prod_{i\in S}i\) 是完全平方数,并最 ...
- Solution -「CF 923F」Public Service
\(\mathscr{Description}\) Link. 给定两棵含 \(n\) 个结点的树 \(T_1=(V_1,E_1),T_2=(V_2,E_2)\),求一个双射 \(\varph ...
随机推荐
- Windows下如何用virtualenv创建虚拟环境
虚拟环境可以有效的解决不同项目需要不同环境的问题,虚拟环境最大的好处就是可以将我们的开发环境进行隔离,让彼此之间不互相受影响.一.Windows下创建虚拟环境1.虚拟环境需要用到的库是virtuale ...
- SQL Server创建用户只能访问指定数据库和视图
我们在给数据库用户赋予权限时,有时候不想让该用户看到太多过程表和过程视图,这时就需要限定用户的访问权限 第一步:创建用户 创建数据库连接后,进入安全性--登录名,单击右键,新建登录名,并设置默认数据库 ...
- python bytecode解析
python bytecode解析 前言 我们的电脑是怎么运行的呢?计算机内部的 CPU 处理器是个硅片,上面雕刻着精心布置的电路,输入特定的电流,就能得到另一种模式的电流,而且模式可以预测,给这些模 ...
- 使用 C# 入门深度学习:Pytorch 基础
教程名称:使用 C# 入门深度学习 作者:痴者工良 地址: https://torch.whuanle.cn 1.2 Pytorch 基础 本文内容介绍 Pytorcn 的基础 API,主要是数组的创 ...
- 知识分享:Air780E软件之UDP应用示例
一.UDP概述 UDP(用户数据报协议,UserDatagramProtocol)是一种无连接的.不可靠的传输层协议,主要用于实现网络中的快速通讯.以下是UDP通讯的主要特点: 1.1 无连接通讯: ...
- Solon MVC 的 @Mapping 用法说明
在 Solon Mvc 里,@Mapping 注解一般是配合 @Controller 和 @Remoting,作请求路径映射用的.且,只支持加在 public 函数 或 类上. 1.注解属性 属性 说 ...
- Linux系统部署Jmeter环境
1.Linu安装Java环境 Jmeter是Java开发的,需要依赖JDK环境,因此我们需提前安装好JDK,安装地址:https://www.oracle.com/technetwork/java/j ...
- MindSpore-2.4版本中的一些新特性
技术背景 在前面的一篇博客中我们介绍了MindSpore-2.4-gpu的安装和其中可能出现的一些问题.这里我们在安装完成之后,可以尝试使用一些MindSpore新版本的特性.那么在安装之后,如果是使 ...
- 用 300 行代码手写提炼 Spring 核心原理 [3]
系列文章 用 300 行代码手写提炼 Spring 核心原理 [1] 用 300 行代码手写提炼 Spring 核心原理 [2] 用 300 行代码手写提炼 Spring 核心原理 [3] 上文 中我 ...
- Java GC 调试手记
摘要 本文记录GC调试的一次实验过程和结果. GC知识要点回顾 问题1:为什么要调试GC参数?在32核处理器的系统上,10%的GC时间导致75%的吞吐量损失.所以在大型系统上,调试GC是以小博大的不错 ...