传送喵

题目喵述

($n,m \leq 10^6$,数据组数 $T \leq 10^3$) 求

$$\prod_{i=1}^n\prod_{j=1}^m fib[gcd(i,j)]$$

其中 $fib[n]$表示斐波那契数列第 $n$项

喵解

数学题太有趣了 (破音 (雾))

首先前面一部分都是套路的东西了

很自然地想到,令
$$g(d)=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==d]$$

$$ans=\prod_{d=1}^nfib[d]^{g(d)}$$

自然地把 $g$给化简一下

$$g(d)=\sum_{i=1}^{\frac n d}\sum_{j=1}^{\frac m d}[gcd(i,j) == 1]$$

相必这个式子你已经能一口说出化简结果了

$$g(d)=\sum_{i=1}^{\frac n d} \mu(i)[\frac n {id}][\frac m {id}]$$

代回原来的式子

$$
\begin{align}
ans&=\prod_{d=1}^nfib[d]^{\sum_{i=1}^{\frac n d} \mu(i)[\frac n {id}][\frac m {id}]}\\
&=\prod_{d=1}^n\prod_{i=1}^{\frac n d} fib[d]^{\mu(i)[\frac n {id}][\frac m {id}]}
\end{align}
$$

又是熟悉的味道,令 $T=id$

$$\prod_{T=1}^n\prod_{d|T} fib[d]^{\mu(\frac n d)[\frac n T][\frac m T]}$$

你如果对时间复杂度有感觉那么你会发现已经什么都结束了

$$\prod_{T=1}^n(\prod_{d|T} fib[d]^{\mu(\frac n d)})^{[\frac n T][\frac m T]}$$

里面的东西可以 $O(nlog^2n)$计算 (有一个算逆元的 log 在里面,不过由于很多 $\mu$是 $0$或者 $1$其实总复杂度是接近 $O(nlogn)$的)

外面的东西显然数论分块,复杂度 $O(T4\sqrt n)$

感觉数学题时间都卡得刚刚好啊,我还是把常数也算里面去吧(

代码

#include<bits/stdc++.h>
#define fo(i, a, b) for (int i = (a); i <= (b); ++i)

#define mod 1000000007
#define N 1000005
#define ll long long
std::bitset<N> vis;
ll mu[N], p[N], tot, up, fib[N], pd[N];
inline ll pow (ll x, ll y = mod - 2)
{
    ll ret = 1;
    while (y)
    {
        if (y & 1) ret = ret * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ret;
}
inline void init ()
{
    up = N - 3;
    fib[0] = 0; fib[1] = 1; pd[0] = 1; pd[1] = 1;
    fo (i, 2, up) {fib[i] = (fib[i - 1] + fib[i - 2]) % mod; pd[i] = 1;}
    mu[1] = 1;
    fo (i, 2, up)
    {
        if (!vis[i])
            p[++tot] = i, mu[i] = -1;
        vis[i] = 1;
        for (int j = 1; j <= tot && i * p[j] <= up; ++j)
        {
            vis[i * p[j]] = 1;
            if (!(i % p[j])) {break;}
            mu[i * p[j]] = -mu[i];
        }
    }
    fo (d, 1, up)
        for (int T = d, div = 1; T <= up; T += d, ++div) // div = T / d
            if (mu[div])
                pd[T] = pd[T] * ((mu[div] == 1) ? fib[d] : pow(fib[d])) % mod;
    fo (i, 2, up)
        pd[i] = pd[i] * pd[i - 1] % mod;
}
int main()
{
    int T;
    scanf("%d", &T);
    init();
    while (T--)
    {
        ll n, m, ans = 1;
        scanf("%lld %lld", &n, &m);
        if (n > m) std::swap(n, m);
        for (int i = 1, j; i <= n; i = j + 1)
        {
            j = std::min(n / (n / i), m / (m / i));
            ans = ans * pow(pd[j] * pow(pd[i - 1]) % mod, (n / i) * (m / i) % (mod - 1)) % mod;
        }
        printf("%lld\n", ans);
    }
    return 0;
}
分类: 文章

quhengyi11

AFO 有缘再见

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注