Solution -「JZOJ #5457」项链
给定一条有 个点的圆环和 中颜色, 求在位置旋转, 位置翻转, 颜色旋转等价的意义下, 本质不同的染色方案数.
数据组数 , .
颜色旋转 ... 那么它就不是颜色了, 就用 Burnside 就行.
首先需要明确的是, 我们的变换群长什么样子. 以 的情况为例:
第一组是位置旋转, 第二组是位置对称翻转, 第三组是颜色旋转, 是笛卡尔积.
Burnside, 考虑不动点. 假设某个 (位置, 颜色) 的映射对为 , 位置 的颜色为 , 那么不动点需要满足 . 先来研究 是旋转置换的情况. 通过一些形象的观察可以发现, 设 的轮换大小为 , 的轮换大小为 , 则不动点存在当且仅当 . 此时对于 的一个环, 只要确定其中一个位置的颜色, 就可以根据 唯一确定环上其他点的颜色, 此时环的方案数为 .
因此, 枚举 , 我们可以得到 是旋转置换时的不动点总数 (式子里的 是欧拉函数 w):
此后, 对于对称置换的 , 需要讨论一下奇偶性:
- , 此时所有置换的都有一个 的轮换, 因此 . 总不动点数为 .
- , 当对称轴放在两个点上时, 和前一种一样, 总不动点数为 ; 当对称轴放在两对点中间时, 所有 , 但是 , 所以还是有 , 总不动点数为 .
- , 当对称轴放在两个点上时还是 ; 当对称轴放在两对点中间时, 可以取 或 , 总不动点数为 .
置换群大小为 , 所以答案为 . 计算上需要 Pollard-Rho, 精细处理 , 顺便预处理 的光速幂, 可以做到 .
/*+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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现