[题解]斐波那契的最小公倍数

小游者,真神人也,左马桶,右永神,会执利笔破邪炁,何人当之?A small swimmer is a God.The left toilet and the right eternal Godcan break the evil energy with a sharp pen.Who can resist him? 小遊者は、神であり、左便器、右永神であり鋭いペンを持って真実を突き刺している。誰が彼に抵抗できるだろうか? Petit voyageur, est Dieu aussi, toilettes gauche, Dieu éternel droit,peut tenir un stylo tranchant pour briser le mal, qui devrait le faire?Der Direktor ist wirklich ein Gottmit einer Toilette links und Yongshen rechtsder einen spitzen Stift hältum die Wahrheit zu durchdringen.Wer kann ihm widerstehen? Ein kleiner Schwimmer ist ein Gott.Die linke Toilette und der rechte ewige Gott können die böse Energie mit einem scharfen Stift brechen.Wer sollte es sein?对曰:“无人,狗欲当之,还请赐教!”

题解

直接算每个质数的指数,对于每个质数 pi,设 F(p,ai) 表示斐波那契数列的 F(ai) 含有 p 多少。

max{F(p,ai)}=TU(1)|T|+1min{F(p,aj)|ajT}

发现是 lcmgcd 的容斥:

lcmF(ai)=TUgcd(F(ai))(1)|T|+1=TUF(gcd(ai))(1)|T|+1

设在 {ai} 中选择 k 个数,他们的 gcdd 的方案数为 g(k,d),是 d 的倍数的方案数为 f(k,d),那么显然有

f(k,n)=dng(k,d)g(k,n)=ndμ(dn)f(k,d)

而我们要求的是

lcm=i=1F(i)j=1n(1)j+1×g(j,i)

专注于指数的运算:

j=1n(1)j+1g(j,i)=j=1n(1)j+1idμ(di)f(j,d)=idμ(di)j=1n(1)j+1f(j,d)

{ai}d 的倍数有 cnt(d) 个,那么 f(j,d)=(cnt(d)j),继续

()=idμ(di)j=1n(1)j+1(cnt(d)j)

显然 cnt(d)n,因此可以将后面的东西改一下

()=idμ(di)j=1cnt(d)(1)j+1(cnt(d)j)

注意到 j=0cnt(d)(1)j+1(cnt(d)d)=1×j=0cnt(d)(1)j(cnt(d)j)=(11)cnt(d)=0,因此 j=1cnt(j)(1)j+1(cnt(d)j)=[cnt(j)>0],所以

()=idμ(di)[cnt(d)>0]

对于每一个 F(i),都计算一下它头顶上的系数,直接暴力枚举 d 就行了,因为这是 O(AlnA) 的,其中 A=maxai.

参考代码

/** @author __Elaina__ */

// #pragma GCC optimize("Ofast")
// #pragma GCC optimize("inline")
// #define GCC optimize(2)
// #define GCC optimize(3)

#include <bits/stdc++.h>
using namespace std;

// #define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define masdf(...) fprintf(stderr, __VA_ARGS__)

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI ((char)getchar())
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}
template<class T> inline T listMax(const T& x) { return x; }
template<class T, class... Args> inline T listMax(const T& x, const Args&... args) {
    return max(x, listMax(args...));
}
template<class T> inline T listMin(const T& x) { return x; }
template<class T, class... Args> inline T listMin(const T& x, const Args&... args) {
    return min(x, listMin(args...));
}

} // namespace Elaina
using namespace Elaina;

const int Maxn = 1e6;
const int mod = 1e9 + 7;

inline int qkpow(int a, int n) {
    int ret = 1;
    for (; n > 0; n >>= 1, a = (int)(1ll * a * a % mod))
        if (n & 1) ret = (int)(1ll * ret * a % mod);
    return ret;
}

int a[Maxn + 5], n;
int cnt[Maxn + 5], buc[Maxn + 5];

bool vis[Maxn + 5];
int prime[Maxn + 5], mu[Maxn + 5];
inline void sieve() {
    vis[1] = true, mu[1] = 1;
    rep (i, 2, Maxn) {
        if (!vis[i]) prime[++*prime] = i, mu[i] = -1;
        for (int j = 1; j <= *prime && i * prime[j] <= Maxn; ++j) {
            vis[i * prime[j]] = true;
            if (i % prime[j] == 0) { mu[i * prime[j]] = 0; break; }
            mu[i * prime[j]] = -mu[i];
        }
    }
}

signed main() {
    readin(n);
    rep (i, 1, n) ++buc[readret(1)];
    rep (i, 1, Maxn)
        for (int j = i; j <= Maxn; j += i)
            cnt[i] += buc[j];
    sieve();
    int fl = 0, fc = 1, ans = 1, tmp;
    rep (i, 1, Maxn) {
        int p = 0;
        for (int d = i; d <= Maxn; d += i) if (cnt[d] > 0) p += mu[d / i];
        if (p < 0) tmp = qkpow(fc, mod - 2), p = -p;
        else tmp = fc;
        ans = (int)(1ll * ans * qkpow(tmp, p) % mod);
        tmp = (fl + fc) % mod, fl = fc, fc = tmp;
    }
    writln(ans);
    return 0;
}
posted @   Arextre  阅读(128)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示