[bzoj4816][Sdoi2017]数字表格

题目大意:有$T(Tleqslant 1000)$组数据,每组数据给你$n,m(1leqslant n,m leqslant 10^6)$,求出$displaystyleprodlimits_{i=1}^n displaystyleprodlimits_{j=1}^m F[(i,j)]$($F(i)$为$fibonacci$数列第$i$项)

题解:下文中假设$n leqslant m$
$$
defdprod{displaystyleprodlimits}\
defdsum{displaystylesumlimits}\
dprod_{i=1}^ndprod_{j=1}^m F[(i,j)]=dprod_{d=1}^n F(d)^{sum_{i=1}^nsum_{j=1}^m [(i,j)==d]}\
令g(p)=dsum_{i=1}^ndsum_{j=1}^m [(i,j)==p]\
egin{align*}
令G(p)&=dsum_{p|k}g(k)\
    &=dsum_{p|k}dsum_{i=1}^ndsum_{j=1}^m [(i,j)==k]\
    &=dsum_{i=1}^ndsum_{j=1}^m [p|(i,j)]\
    &=leftlfloordfrac{n}{p} ight floorcdotleftlfloordfrac{m}{p} ight floor
end{align*}\
$$

$$
defdsum{displaystylesumlimits}\
莫比乌斯反演得:\
egin{align*}
g(p)&=dsum_{p|k}muig(dfrac{k}{p}ig)G(p)\
    &=dsum_{p|k}muig(dfrac{k}{p}ig)leftlfloordfrac{n}{p} ight floorcdotleftlfloordfrac{m}{p} ight floor\
    &=dsum_{i=1}^nmu(i)leftlfloordfrac{n}{icdot p} ight floorcdotleftlfloordfrac{m}{icdot p} ight floor
end{align*}
$$

$$
defdprod{displaystyleprodlimits}\
defdsum{displaystylesumlimits}\
egin{align*}
dprod_{i=1}^ndprod_{j=m}^m F[(i,j)]&=dprod_{d=1}^n F(d)^{sum_{i=1}^nsum_{j=1}^m [(i,j)==d]}\
        &=dprod_{d=1}^nF(d)^{g(d)}\
        &=dprod_{d=1}^nF(d)^{sum_{i=1}^nmu(i)lfloorfrac{n}{i p} floorcdotlfloorfrac{m}{i p} floor}\
        &=dprod_{d=1}^ndprod_{d|k}F(d)^{muig(dfrac{k}{d}ig)iglfloordfrac{n}{k}ig flooriglfloordfrac{m}{k}ig floor}\
        &=dprod_{k=1}^nigg(dprod_{d|k}F(d)^{muig(dfrac{k}{d}ig)}igg)^{iglfloordfrac{n}{k}ig flooriglfloordfrac{m}{k}ig floor}\
end{align*}\
$$

$$
defdprod{displaystyleprodlimits}\
令s[k]=dprod_{d|k}F(d)^{muig(dfrac{k}{d}ig)}\
预处理出s,然后整除分块就行了
$$

卡点:



C++ Code:

#include <cstdio>
#include <cstring>
#define maxn 1000010
using namespace std;
const int mod = 1000000007;
int F[maxn], invF[maxn], s[maxn], invs[maxn];
int plist[maxn], miu[maxn], ptot;
bool isp[maxn];
int pw(int base, int p) {
    base %= mod, p %= mod - 1;
    int ans = 1;
    for (; p; p >>= 1, base = 1ll * base * base % mod)
        if (p & 1) ans = 1ll * ans * base % mod;
    return ans;
}
int inv(int a) {
    return pw(a, mod - 2);
}
void sieve(int n) {
    invs[0] = s[0] = s[1] = 1;
    F[0] = 0; invF[1] = F[1] = miu[1] = 1;
    for (int i = 2; i < n; i++) {
        s[i] = 1;
        F[i] = (F[i - 1] + F[i - 2]) % mod;
        invF[i] = inv(F[i]);
        if(!isp[i]) plist[ptot++] = i, miu[i] = -1;
        for (int j = 0; j < ptot && i * plist[j] < n; j++) {
            int tmp = i * plist[j];
            isp[tmp] = true;
            if (i % plist[j] == 0) {
                miu[tmp] = 0;
                break;
            }
            miu[tmp] = -miu[i];
        }
    }
    for (int i = 1; i < n; i++) {
        for (int j = 1, k = i; k < n; j++, k += i) {
            if (miu[j] == 1) s[k] = 1ll * s[k] * F[i] % mod;
            if (miu[j] == -1) s[k] = 1ll * s[k] * invF[i] % mod;
        }
    }
    for (int i = 1; i < n; i++) {
        s[i] = 1ll * s[i] * s[i - 1] % mod;
        invs[i] = inv(s[i]);
    }
}
inline int min(int a, int b) {return a < b ? a : b;}
int solve(int n, int m) {
    int tmp = min(n, m), ans = 1, j;
    for (int i = 1; i <= tmp; i = j + 1) {
        j = min(n / (n / i), m / (m / i));
        ans = 1ll * ans * pw(1ll * s[j] * invs[i - 1] % mod, 1ll * (n / i) * (m / i) % (mod - 1)) % mod;
    }
    return ans;
}
int Tim, n, m;
int main() {
    sieve(maxn);
    scanf("%d", &Tim);
    while (Tim --> 0) {
        scanf("%d%d", &n, &m);
        printf("%d
", solve(n, m));
    }
    return 0;
}




原文地址:https://www.cnblogs.com/Memory-of-winter/p/9522451.html