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

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

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

题目传送门:洛谷P3704

题意简述:

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

(T) 组数据。

题解:

喜闻乐见的推式子时间。

不失一般性,假设 (Nle M) 。

[egin{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 ight] ight)}end{aligned}]

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

[egin{align*}&= sum_{i=1}^{N}sum_{j=1}^{M}left[gcd(i,j)=k ight]\&= sum_{i=1}^{leftlfloorfrac{N}{k} ight floor}sum_{j=1}^{leftlfloorfrac{M}{k} ight floor}left[gcd(i,j)=1 ight]\&= sum_{d=1}^{leftlfloorfrac{N}{k} ight floor}mu(d)leftlfloorfrac{N}{kd} ight floorleftlfloorfrac{M}{kd} ight floorend{align*}]

所以

[egin{align*} &= prod_{k=1}^{N}{F_{k}}^{left(sum_{d=1}^{leftlfloorfrac{N}{k} ight floor}mu(d)leftlfloorfrac{N}{kd} ight floorleftlfloorfrac{M}{kd} ight floor ight)}\ &= prod_{T=1}^{N}left(prod_{k|T}{F_{k}}^{mu(frac{T}{k})} ight)^{leftlfloorfrac{N}{T} ight floorleftlfloorfrac{M}{T} ight floor} end{align*}]

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

[=prod_{T=1}^{N}{f(T)}^{leftlfloorfrac{N}{T} ight floorleftlfloorfrac{M}{T} ight floor}]

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

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

正确的时间复杂度应该是 (Theta(N(log N+log mod)+Tsqrt{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
", A);
73     }
74     return 0;
75 }
原文地址:https://www.cnblogs.com/PinkRabbit/p/10011541.html