BZOJ 4833: [Lydsy1704月赛]最小公倍佩尔数(数论 + 最值反演)

题面

(1+2)n=e(n)+f(n)2 ,其中 e(n),f(n) 都是整数,显然有 (12)n=e(n)f(n)2

g(n) 表示 f(1),f(2)f(n) 的最小公倍数,给定两个正整数 np ,其中 p 是质数,并且保证 f(1),f(2)f(n) 在模 p 意义下均不为 0 .

请计算i=1nig(i) .其在模 p 的值。

T210,n3×106

题解

其实它就是给你了 f(n) 的特征方程,其实可以解出来,具体来说 递推式到通相式 直接待定系数,解回去就把系数代回去就行了。

但是没有必要,f(n) 是个能打表的东西。

f(n)={0,n=01,n=12f(n1)+f(n2)otherwise

然后它具有和 fib(i) 一样的性质, gcd(f(i),f(j))=f(gcd(i,j))

至于证明,可以类似 fib(i) 的性质证明。

然后考虑最值反演:

不会的话可以看我 这篇博客

然后我们可以把这个对于 lcm 放到指数上来就是所有指数的 max ,那么我们可以用最值反演变成 min ,也就是 gcd

形式如下

lcm(S)=TS,Tgcd(T)(1)|T|1

然后我们利用这个性质进行推导。

(1)g(n)=TS,TgcdxT{f(x)}(1)|T|+1(2)=TS,Tf(gcd(T))(1)|T|+1

然后考虑构造一个函数 h 满足

f(n)=d|nh(d)

由于在模素数意义下,所以必定存在 h 满足要求。

然后我们考虑每个 h(d) 的贡献:

(3)g(n)=d=1nh(d)TS,T[d|gcd(T)](1)|T|+1(4)=d=1nh(d)

至于上面那个系数为什么 =1 呢?可以考虑 T 集合中所有为 d 倍数的数构成的所有集合,刚好是 2k1 的,除去空集,那么剩下的一一抵消,剩下一个 1 的贡献。

考虑求出 h 是可以枚举倍数来优化到 O(nlnn) 的。

具体来说假设我们 <n 的所有 h 都求好了,那么当前的 h(n)=f(n)d|n,dn1h(d)

其实可以用莫比乌斯反演推回去的,但没必要筛 μ

那么能不能用线性筛优化到 O(n) 呢?似乎是不行的,因为 h 不是积性的,我们知道 h(i)h(p) 无法推出 h(i×p)

然后最后复杂度就是 O(nlnn) 的。

总结

对于有些看起来不太好求的 lcm 题,考虑最值反演。然后考虑构造积性函数,最后求出积性函数求回来就行了。

代码

/************************************************************** Problem: 4833 User: zjp_shadow Language: C++ Result: Accepted Time:5908 ms Memory:13024 kb ****************************************************************/ #include <bits/stdc++.h> #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i) #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i) #define Set(a, v) memset(a, v, sizeof(a)) #define Cpy(a, b) memcpy(a, b, sizeof(a)) #define debug(x) cout << #x << ": " << (x) << endl #define DEBUG(...) fprintf(stderr, __VA_ARGS__) using namespace std; typedef long long ll; template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;} template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;} inline int read() { int x(0), sgn(1); char ch(getchar()); for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1; for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48); return x * sgn; } void File() { #ifdef zjp_shadow freopen ("4883.in", "r", stdin); freopen ("4883.out", "w", stdout); #endif } const int N = 1e6 + 1e3; int Mod, h[N], g[N], ans[N]; ll fpm(ll x, int power) { ll res = 1; for (; power; power >>= 1, (x *= x) %= Mod) if (power & 1) (res *= x) %= Mod; return res; } void Solve(int maxn) { h[1] = 1; For (i, 2, maxn) h[i] = (h[i - 1] * 2ll + h[i - 2]) % Mod; For (i, 2, maxn) { int inv = fpm(h[i], Mod - 2); for (int j = i * 2; j <= maxn; j += i) h[j] = 1ll * h[j] * inv % Mod; } g[0] = 1; int ans = 0; For (i, 1, maxn) { g[i] = 1ll * g[i - 1] * h[i] % Mod; ans = (ans + 1ll * g[i] * i) % Mod; } printf ("%d\n", ans); } int main () { File(); int cases = read(); while (cases --) { int n = read(); Mod = read(); Solve(n); } return 0; }

__EOF__

本文作者zjp_shadow
本文链接https://www.cnblogs.com/zjp-shadow/p/9754566.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zjp_shadow  阅读(356)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示