题解 P3704 【[SDOI2017]数字表格】
在博客园食用更佳:https://www.cnblogs.com/PinkRabbit/p/10011541.html。
题意简述:
求
共有
题解:
喜闻乐见的推式子时间。
不失一般性,假设
右上角的指数部分是老套路了。
所以
令
则
外层数论分块求出。内层的
注意实现的时候的时间复杂度,我因为实现多了快速幂的一个
正确的时间复杂度应该是
#include<cstdio>
#include<algorithm>
using namespace std;
#define mod 1000000007
#define LL long long
int Pow(int b, LL e) {
if (e < 0) e += mod - 1;
int a = 1;
for (; e; b = (LL)b * b % mod, e >>= 1)
if (e & 1) a = (LL)a * b % mod;
return a;
}
bool ip[1000005];
int p[80005], pc;
int mu[1000005];
int f[1000005], fr[1000005];
void init() {
ip[1] = 1;
mu[1] = 1;
for (int i = 2; i <= 1000000; ++i) {
if (!ip[i]) {
p[++pc] = i;
mu[i] = -1;
}
for (int j = 1; j <= pc && (LL)p[j] * i <= 1000000; ++j) {
register int k = p[j] * i;
ip[k] = 1;
if (i % p[j]) mu[k] = -mu[i];
else break;
}
}
for (int i = 1; i <= 1000000; ++i)
f[i] = 1, fr[i] = 1;
int A = 1, B = 0;
for (int i = 1; i <= 1000000; ++i) {
B = (A + B) % mod;
A = (B - A + mod) % mod;
int G[3] = {Pow(B, -1), 1, B};
for (int j = i, k = 1; j <= 1000000; j += i, ++k) {
f[j] = (LL)f[j] * G[mu[k] + 1] % mod,
fr[j] = (LL)fr[j] * G[1 - mu[k]] % mod;
}
}
f[0] = fr[0] = 1;
for (int i = 1; i <= 1000000; ++i)
f[i] = (LL)f[i - 1] * f[i] % mod,
fr[i] = (LL)fr[i - 1] * fr[i] % mod;
}
int main() {
init();
int T;
scanf("%d", &T);
while (T--) {
int N, M;
scanf("%d%d", &N, &M);
if (N > M) swap(N, M);
int A = 1;
for (int i = 1, j; i <= N; i = j + 1) {
j = min(N / (N / i), M / (M / i));
A = (LL)A * Pow((LL)f[j] * fr[i - 1] % mod, (LL)(N / i) * (M / i)) % mod;
}
printf("%d\n", A);
}
return 0;
}