[SDOI2017]数字表格 题解

Description

\(T\) 组询问,每组询问给出 \(n,m\) ,求 \(\prod_{i=1}^n\prod_{j=1}^m f_{\gcd(i,j)}\),其中 \(f\) 为斐波那契数列。
\(T\le10^3,n,m\le10^6\)

Sol

我们先枚举 \(\gcd(i,j)\) 的值,将原式转化为

\[\prod_{i=1}^n\prod_{j=1}^n\prod_{d=1}^n f_d[\gcd(i,j)=d] \]

交换求积符号并将 \(\prod\) 化为 \(\sum\),将原式转化为

\[\prod_{d=1}^n f_d^{\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac md\rfloor}[gcd(i,j)=1]} \]

把指数上的式子拿出来

\[\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac md\rfloor}[gcd(i,j)=1] \]

\[=\sum_{k=1}^{\lfloor\frac nd\rfloor}\mu(k)\lfloor\frac i{kd}\rfloor\lfloor\frac j{kd}\rfloor \]

然后我们就得到了一个可以 \(O(Tn\sqrt n)\) 计算的式子

\[\prod_{d=1}^n f_d^{\sum_{k=1}^{\lfloor\frac nd\rfloor}\mu(k)\lfloor\frac i{kd}\rfloor\lfloor\frac j{kd}\rfloor} \]

我们设 \(kd=u\),枚举 \(u\) ,将原式转化为

\[\prod_{u=1}^n(\prod_{k|u}f_{\frac uk}^{\mu(k)})^{\lfloor\frac nu\rfloor\lfloor\frac mu\rfloor} \]

\(O(n\log n)\) 预处理\(\prod_{k|u}f_{\frac uk}^{\mu(k)})\) 即可在 \(O(T\sqrt n\log Mod)\) 的复杂度内通过本题。

Code

#include<bits/stdc++.h>
#define int long long
#define Mod 1000000007
using namespace std;
int Read() {
	int x = 0, f = 1; char ch = getchar();
	while(!isdigit(ch)) {if(ch == '-')  f = -1; ch = getchar();}
	while(isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();}
	return x * f;
}
int qpow(int a, int b) {
    int res = 1;
    while(b) {
        if(b & 1)  res = res * a % Mod;
        a = a * a % Mod;
        b >>= 1;
    }
    return res;
}
int n, m, prime[1000005], isp[1000005], mu[1000005], f[1000005], g[1000005], F[1000005], prod[1000005], cnt;
void prework() {
    f[1] = g[1] = 1, f[0] = 0; mu[1] = 1; F[1] = 1; prod[0] = 1;
    for(int i = 2; i <= 1000000; i++) {
        if(!isp[i])  prime[++cnt] = i, mu[i] = -1; F[i] = 1;
        f[i] = (f[i - 1] + f[i - 2]) % Mod; g[i] = qpow(f[i], Mod - 2);
        for(int j = 1; j <= cnt && i * prime[j] <= 1000000; j++) {
            isp[i * prime[j]] = 1;
            mu[i * prime[j]] = -mu[i];
            if(i % prime[j] == 0) {mu[i * prime[j]] = 0; break;}
        }
    }
    for(int i = 1; i <= 1000000; i++) {
        if(mu[i])  for(int j = i; j <= 1000000; j += i)
            F[j] = F[j] * (mu[i] == 1 ? f[j / i] : g[j / i]) % Mod;
        prod[i] = prod[i - 1] * F[i] % Mod;
    }
}
int solve(int x, int y) {
    int pro, ans = 1;
    for(int l = 1, r; l <= x; l = r + 1) {
        r = min(x / (x / l), y / (y / l));
        pro = prod[r] * qpow(prod[l - 1], Mod - 2) % Mod;
        ans = ans * qpow(pro, (x / l) * (y / l) % (Mod - 1)) % Mod;
    }
    return ans;
}
signed main() {
    prework();
    int T = Read();
    while(T--) {
        int a = Read(), b = Read();
        if(a > b)  swap(a, b);
        printf("%lld\n", solve(a, b));
    }
	return 0;
}
posted @ 2020-10-16 15:31  verjun  阅读(81)  评论(0编辑  收藏  举报