您的位置:首页 > 其它

BZOJ 4816 数字表格

2017-05-23 17:49 190 查看
数字表格

【问题描述】

Doris刚刚学习了fibonacci数列。用f[i]表示数列的第i项,那么

f[0]=0

f[1]=1

f
=f[n-1]+f[n-2],n>=2

Doris用老师的超级计算机生成了一个n×m的表格,第i行第j列的格子中的数是f[gcd(i,j)],其中gcd(i,j)表示i,

j的最大公约数。Doris的表格中共有n×m个数,她想知道这些数的乘积是多少。答案对10^9+7取模。

【输入格式】

有多组测试数据。

第一个一个数T,表示数据组数。

接下来T行,每行两个数n,m

T<=1000,1<=n,m<=10^6

【输出格式】

输出T行,第i行的数是第i组数据的结果

【样例输入】

3

2 3

4 5

6 7

【样例输出】

1

6

960

题解:




可以用O(nlog2n)的普通筛法预处理出来的

那么剩下的部分就是逆元和分块了

1 #include<cmath>
2 #include<cstdio>
3 #include<cstdlib>
4 #include<cstring>
5 #include<iostream>
6 #include<algorithm>
7 using namespace std;
8 const int maxt = 1e3 + 233;
9 const int maxn = 1e6 + 233;
10 const int mod = 1e9 + 7;
11 int T;
12 int n[maxt], m[maxt];
13 int f[maxn], g[maxn], inv[maxn];
14 bool vis[maxn];
15 int p[maxn], mu[maxn];
16 int suma[maxn], sumb[maxn];
17 inline void Scan(int &x)
18 {
19     char c;
20     bool o = false;
21     while(!isdigit(c = getchar())) o = (c != '-') ? o : true;
22     x = c - '0';
23     while(isdigit(c = getchar())) x = x * 10 + c - '0';
24     if(o) x = -x;
25 }
26 inline void Fib(int n)
27 {
28     f[0] = 0, f[1] = 1;
29     for(int i = 2; i <= n; ++i)
30         f[i] = (f[i - 1] + f[i - 2]) % mod;
31 }
32 inline void Mobius(int n)
33 {
34     mu[1] = 1;
35     int num = 0;
36     for(int i = 2; i <= n; ++i)
37     {
38         if(!vis[i])
39         {
40             p[++num] = i;
41             mu[i] = -1;
42         }
43         for(int j = 1; j <= num; ++j)
44         {
45             int s = i * p[j];
46             if(i * p[j] > n) break;
47             vis[s] = true;
48             if(!(i % p[j]))
49             {
50                 mu[s] = 0;
51                 break;
52             }
53             else mu[s] = -mu[i];
54         }
55     }
56 }
57 inline int Pow(int x, int n)
58 {
59     int sum = 1;
60     while(n)
61     {
62         if(n & 1) sum = (long long) sum * x % mod;
63         x = (long long) x * x % mod;
64         n >>= 1;
65     }
66     return sum;
67 }
68 inline void Inv(int n)
69 {
70     for(int i = 1; i <= n; ++i)
71         inv[i] = Pow(f[i], mod - 2);
72 }
73 inline void Part(int n)
74 {
75     for(int i = 1; i <= n; ++i) g[i] = 1;
76     for(int i = 2; i <= n; ++i)
77         for(int j = i; j <= n; j += i)
78         {
79             if(mu[j / i] == -1) g[j] = (long long) g[j] * inv[i] % mod;
80             if(mu[j / i] == 1) g[j] = (long long) g[j] * f[i] % mod;
81         }
82 }
83 inline void Sum(int n)
84 {
85     suma[0] = 1;
86     for(int i = 1; i <= n; ++i) suma[i] = (long long) suma[i - 1] * g[i] % mod;
87     sumb
= Pow(suma
, mod - 2);
88     for(int i = n - 1; i >= 1; --i) sumb[i] = (long long) sumb[i + 1] * g[i + 1] % mod;
89     sumb[0] = 1;
90 }
91 inline int Ans(int n, int m)
92 {
93     int last;
94     int ans = 1;
95     int c = min(n, m);
96     for(int i = 1; i <= c; i = last + 1)
97     {
98         last = min(n / (n / i), m / (m / i));
99         ans = (long long) ans * Pow((long long) suma[last] * sumb[i - 1] % mod, (long long) (n / i) * (m / i) % (mod - 1)) % mod;
100     }
101     return ans;
102 }
103 int main()
104 {
105     Scan(T);
106     int maxn = 0;
107     for(int i = 1; i <= T; ++i)
108     {
109         Scan(n[i]), Scan(m[i]);
110         maxn = max(maxn, max(n[i], m[i]));
111     }
112     Fib(maxn);
113     Mobius(maxn);
114     Inv(maxn);
115     Part(maxn);
116     Sum(maxn);
117     for(int i = 1; i <= T; ++i) printf("%d\n", Ans(n[i], m[i]));
118 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: