[BZOJ4816][Sdoi2017]数字表格 数学

考虑每个 fi 对答案的贡献,就能得到式子

k=1nfd|kμ(d)nkdmkdk

转化成枚举 kd ,令 T=kd
T=1n(d|Tfμ(Td)d)nTmT

预处理小括号内的部分,令 gT=d|Tfμ(Td)d
单次询问只需要回答
T=1ngnTmTT

易证 nT mT 只有 O(N) 种取值,分段计数即可
预处理 O(NN) ,询问 O(TNlog2N) ,log来自快速幂

#include <bits/stdc++.h>
#define mod 1000000007
#define N 1000050
#define tp 1000000
using namespace std;
typedef long long LL;
inline int rd() {int r;scanf("%d",&r);return r;}

bool np[N];
int eu[N],pr[N],g[N],fib[N],sum[N],siv[N],cnt,n,m,ans;
inline int qp(int a,long long b) {
    int ret = 1;
    while (b) {
        if (b&1) ret = 1LL * ret * a % mod;
        b >>= 1, a = 1LL * a * a % mod;
    }
    return ret;
}

void preset() {
    eu[1] = 1;
    for (int i=2;i<=tp;i++) {
        if (!np[i]) pr[++cnt] = i, eu[i] = -1;
        for (int j=1;j<=cnt && pr[j]*i<=tp;j++) {
            np[i*pr[j]] = 1;
            if (i%pr[j] == 0) {
                eu[i*pr[j]] = 0;
                break;
            }
            eu[i*pr[j]] = -eu[i];
        }
    }   


    fib[0] = 0, fib[1] = 1;
    for (int i=2;i<=tp;i++) fib[i] = (fib[i-1] + fib[i-2]) % mod;
    for (int i=1;i<=tp;i++) g[i] = 1;   

    sum[0] = siv[0] = 1;
    for (int i=1;i<=tp;++i) {
        int cur = fib[i];
        int inv = qp(cur, mod-2);
        for (int j=1;i*j<=tp;++j) {
            if (eu[j] == 0) continue;
            g[i*j] = eu[j] == 1 ?
                1LL * g[i*j] * cur % mod:
                1LL * g[i*j] * inv % mod;
        }
        sum[i] = 1LL * sum[i-1] * g[i] % mod;
        siv[i] = 1LL * siv[i-1] * qp(g[i], mod-2) % mod;
    }

}

void solve() {
    n = rd(), m = rd(), ans = 1;
    if (n>m) swap(n,m);
    for (int i=1,lst,cur;i<=n;i=lst+1) {
        lst = min(n/(n/i), m/(m/i));
        cur = 1LL * sum[lst] * siv[i-1] % mod;
        ans = 1LL * ans * qp(cur, 1LL*(n/i)*(m/i)) % mod;
    }
    printf("%d\n",ans);
}

int main() {
    freopen("product.in","r",stdin);
    freopen("product.out","w",stdout);
    preset();
    for (int T=rd();T;T--) solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值