• 【题解】洛谷 P3704 [SDOI2017]数字表格


    前置

    幂转和

    (prodlimits_{i} g^{d_i}=g^{sumlimits_{i}d_i})(g) 是常数,或者至少在这次 (prod) 中不会变化

    gcd 的套路卷积

    [egin{aligned} ecause[x==1]&=sumlimits_{d|x}mu(d)\ herefore[gcd(x, y)==1]&=sumlimits_{d|gcd(x, y)}mu(d) \&=sumlimits_{d}mu(d)[d|x][d|y] end{aligned} ]

    此时常常可以将 (sumlimits_{d}mu(d)) 提到式子最前面,而 ([d|x][d|y]) 常常可以与枚举 (x, y) 的上界进行抵消,就像这样:

    (sumlimits_{x=1}^{n}[x|d]mathbf{f}(x)=sumlimits_{x=1}^{lfloorfrac{n}{d} floor}mathbf{f}(xd))

    而当 (mathbf{f}(x)=mathbf{id_0}(x)=mathbf{1}(x)=1) 时,原式 (=lfloorfrac{n}{d} floor)

    推公式

    [egin{aligned} prodlimits_{i=1}^{n}prodlimits_{j=1}^{m}f_{gcd(i,j)} &=prodlimits_{i=1}^{n}prodlimits_{j=1}^{m}prodlimits_{g=1}^{min(i, j)}f_g^{[gcd(i, j)==g]} \&=prodlimits_{g=1}^{min(n, m)}f_g^{sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i, j)==g]} \&=prodlimits_{g=1}^{min(n, m)}f_g^{sumlimits_{i=1}^{lfloorfrac{n}{g} floor}sumlimits_{j=1}^{lfloorfrac{m}{g} floor}[gcd(i, j)==1]} \&=prodlimits_{g=1}^{min(n, m)}f_g^{sumlimits_{i=1}^{lfloorfrac{n}{g} floor}sumlimits_{j=1}^{lfloorfrac{m}{g} floor}sumlimits_{d|gcd(i, j)}mu(d)} \&=prodlimits_{g=1}^{min(n, m)}f_g^{sumlimits_{i=1}^{lfloorfrac{n}{g} floor}sumlimits_{j=1}^{lfloorfrac{m}{g} floor}sumlimits_{d}[d|i][d|j]mu(d)} \&=prodlimits_{g=1}^{min(n, m)}f_g^{sumlimits_{d}mu(d)sumlimits_{i=1}^{lfloorfrac{n}{g} floor}[d|i]sumlimits_{j=1}^{lfloorfrac{m}{g} floor}[d|j]} \&=prodlimits_{g=1}^{min(n, m)}f_g^{sumlimits_{d}mu(d)lfloorfrac{n}{gd} floorlfloorfrac{m}{gd} floor} \&=prodlimits_{g=1}^{min(n, m)}f_g^{sumlimits_{g|T}mu(frac{T}{g})lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor}&( exttt{代换 }T=gd) \&=prodlimits_{T}prodlimits_{g|T}^{min(n, m)}f_g^{mu(frac{T}{g})lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor} end{aligned} ]

    (mathbf{F}(T)=prodlimits_{g|T}f_g^{mu(frac{T}{g})})

    ( herefore exttt{ 原式}=prodlimits_{T=1}^{min(n, m)}mathbf{F}(T)^{lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor})

    (mathbf{F}(T)) 进行 (Theta(nlog n)) 预处理前缀积

    其余部分用数论分块 (Theta(sqrt{n})) 计算

    代码

    const int N = 1e6 + 7, P = 1e9 + 7;
    
    inline int64 fpow(int64 a, int64 b) {
        int64 ret = 1;
        while (b) {
            if (b & 1) ret = ret * a % P;
            a = a * a % P;
            b >>= 1;
        }
        return ret;
    }
    #define inv(x) fpow(x, P - 2)
    
    namespace euler {
        bool IsntPrime[N];
        int prs[N], pcnt, mu[N];
        unsigned a[N];
    
        void init_prs(int n) {
            mu[1] = 1;
            for (int i = 2; i <= n; ++i) {
                if (!IsntPrime[i]) {
                    prs[++pcnt] = i;
                    mu[i] = -1;
                }
                for (int j = 1; j <= pcnt && prs[j] * i <= n; ++j) {
                    IsntPrime[prs[j] * i] = true;
                    if (i % prs[j] == 0) break;
                    mu[prs[j] * i] = -mu[i];
                }
            }
        }
    }
    
    namespace fib {
        int f[N], invf[N];
        void init(int n) {
            invf[1] = f[1] = 1;
            for (int i = 2; i <= n; ++i) {
                f[i] = (f[i - 1] + f[i - 2]) % P;
                invf[i] = inv(f[i]);
            }
        }
    }
    
    namespace F {
        int64 f[N], sum[N];
        void init(int n) {
            for (int g = 0; g <= n; ++g) f[g] = 1;
            sum[0] = 1;
            for (int g = 1; g <= n; ++g) {
                for (int d = 1; d * g <= n; ++d) // T = d * g
                    switch (euler::mu[d]) {
                        case 1: f[g * d] = f[g * d] * fib::f[g] % P; break;
                        case -1: f[g * d] = f[g * d] * fib::invf[g] % P; break;
                    }
                sum[g] = sum[g - 1] * f[g] % P;
                // printf("f[%d] = %lld
    ", g, f[g]);
            }
        }
        int64 prod(int l, int r) {
            return sum[r] * inv(sum[l - 1]) % P;
        }
    }
    
    signed main() {
        euler::init_prs(1e6);
        fib::init(1e6);
        F::init(1e6);
        int T, n, m;
        for (cin >> T; T--;) {
            cin >> n >> m;
            int64 ans = 1;
            for (int l = 1, r, bound = min(n, m); l <= bound; l = r + 1) {
                r = min(n / (n / l), m / (m / l));
                ans = ans * fpow(F::prod(l, r), int64(n / l) * (m / l) % (P - 1)) % P;
            }
            cout << ans << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    Spring MVC 通过ajax实现前后台交互
    一些基础的东西总结一下
    如何在页面中引用自定义标签
    Linux(centos)系统下安装fastdfs安装部署步骤,问题复现 并在java中集成测试demo
    Liunx下修改JVM内存大小
    在liunx下安装配置rabbitMQ详细教程
    Oracle创建用户、角色、授权、建表
    要做小程序的订阅推送 本篇 从小程序到后端!!!
    Thymeleaf入门入门入门入门入门入门入门入门入门入门入门
    git clone 解决Permission Denied (publickey)问题
  • 原文地址:https://www.cnblogs.com/hkxadpall/p/solution-luogu-P3704.html
Copyright © 2020-2023  润新知