bzoj 4816: 洛谷 P3704: [SDOI2017]数字表格

洛谷很早以前就写过了,今天交到bzoj发现TLE了。

检查了一下发现自己复杂度是错的。

题目传送门:洛谷P3704

题意简述:

求 \(\prod_{i=1}^{N}\prod_{j=1}^{M}F_{\gcd(i,j)}\bmod mod\) ,其中 \(F_{i}\) 是斐波那契数列的第 \(i\) 项, \(mod=10^9+7\) 。

\(T\) 组数据。

题解:

喜闻乐见的推式子时间。

不失一般性,假设 \(N\le M\) 。

\[\begin{aligned}&\prod_{i=1}^{N}\prod_{j=1}^{M}F_{\gcd(i,j)} \\=&\prod_{k=1}^{N}{F_{k}}^{\left(\sum_{i=1}^{N}\;\sum_{j=1}^{M}\;\left[\gcd(i,j)=k\right]\right)}\end{aligned}\]

右上角的指数部分是老套路了。

\[\begin{align*}&= \sum_{i=1}^{N}\sum_{j=1}^{M}\left[\gcd(i,j)=k\right]\\&= \sum_{i=1}^{\left\lfloor\frac{N}{k}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{M}{k}\right\rfloor}\left[\gcd(i,j)=1\right]\\&= \sum_{d=1}^{\left\lfloor\frac{N}{k}\right\rfloor}\mu(d)\left\lfloor\frac{N}{kd}\right\rfloor\left\lfloor\frac{M}{kd}\right\rfloor\end{align*}\]

所以

\[\begin{align*} &= \prod_{k=1}^{N}{F_{k}}^{\left(\sum_{d=1}^{\left\lfloor\frac{N}{k}\right\rfloor}\mu(d)\left\lfloor\frac{N}{kd}\right\rfloor\left\lfloor\frac{M}{kd}\right\rfloor\right)}\\ &= \prod_{T=1}^{N}\left(\prod_{k|T}{F_{k}}^{\mu(\frac{T}{k})}\right)^{\left\lfloor\frac{N}{T}\right\rfloor\left\lfloor\frac{M}{T}\right\rfloor} \end{align*}\]

令 \(f(n)=\prod_{d|n}{F_{d}}^{\mu(\frac{n}{d})}\) 。

\[=\prod_{T=1}^{N}{f(T)}^{\left\lfloor\frac{N}{T}\right\rfloor\left\lfloor\frac{M}{T}\right\rfloor}\]

外层数论分块求出。内层的 \(f(T)\) 直接暴力预处理,每个数直接乘到它的倍数中,复杂度 \(\Theta(n\log n)\)。

注意实现的时候的时间复杂度,我因为实现多了快速幂的一个 \(\log\) 被卡了。

正确的时间复杂度应该是 \(\Theta(N(\log N+\log mod)+T\sqrt{N}\log mod)\) 。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 #define mod 1000000007
 6 #define LL long long
 7 
 8 int Pow(int b, LL e) {
 9     if (e < 0) e += mod - 1;
10     int a = 1;
11     for (; e; b = (LL)b * b % mod, e >>= 1)
12         if (e & 1) a = (LL)a * b % mod;
13     return a;
14 }
15 
16 bool ip[1000005];
17 int p[80005], pc;
18 int mu[1000005];
19 int f[1000005], fr[1000005];
20 
21 void init() {
22     
23     ip[1] = 1;
24     mu[1] = 1;
25     
26     for (int i = 2; i <= 1000000; ++i) {
27         if (!ip[i]) {
28             p[++pc] = i;
29             mu[i] = -1;
30         }
31         for (int j = 1; j <= pc && (LL)p[j] * i <= 1000000; ++j) {
32             register int k = p[j] * i;
33             ip[k] = 1;
34             if (i % p[j]) mu[k] = -mu[i];
35             else break;
36         }
37     }
38     
39     for (int i = 1; i <= 1000000; ++i)
40         f[i] = 1, fr[i] = 1;
41     
42     int A = 1, B = 0;
43     for (int i = 1; i <= 1000000; ++i) {
44         B = (A + B) % mod;
45         A = (B - A + mod) % mod;
46         int G[3] = {Pow(B, -1), 1, B};
47         for (int j = i, k = 1; j <= 1000000; j += i, ++k) {
48             f[j] = (LL)f[j] * G[mu[k] + 1] % mod,
49             fr[j] = (LL)fr[j] * G[1 - mu[k]] % mod;
50         }
51     }
52     
53     f[0] = fr[0] = 1;
54     for (int i = 1; i <= 1000000; ++i)
55         f[i] = (LL)f[i - 1] * f[i] % mod,
56         fr[i] = (LL)fr[i - 1] * fr[i] % mod;
57 }
58 
59 int main() {
60     init();
61     int T;
62     scanf("%d", &T);
63     while (T--) {
64         int N, M;
65         scanf("%d%d", &N, &M);
66         if (N > M) swap(N, M);
67         int A = 1;
68         for (int i = 1, j; i <= N; i = j + 1) {
69             j = min(N / (N / i), M / (M / i));
70             A = (LL)A * Pow((LL)f[j] * fr[i - 1] % mod, (LL)(N / i) * (M / i)) % mod;
71         }
72         printf("%d\n", A);
73     }
74     return 0;
75 }

 

转载于:https://www.cnblogs.com/PinkRabbit/p/10011541.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值