在不開題解的情況下,成功騙了30分,以下是騙分的代碼
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
typedef long long LL;
const int N = 1e3 + 6, P = 1e9 + 7;
LL g[N][N], f[N];
LL ksm(LL a, LL b) {
LL ans = 1LL;
for (; b; b >>= 1) {
if (b & 1) ans = ans * a % P;
a = a * a % P;
}
return ans;
}
int gcd(int a, int b) {
return !a ? b : gcd(b % a, a);
}
void Prepare() {
f[0] = 0, f[1] = 1;
for (int i = 2; i <= 1000; i++)
f[i] = (f[i-1] + f[i-2]) % P;
for (int i = 1; i <= 1000; i++)
g[1][i] = g[i][1] = 1;
for (int i = 2; i <= 1000; i++)
for (int j = 2; j <= 1000; j++)
g[i][j] = g[i][j-1] * g[i-1][j] % P * f[gcd(i,j)] % P * ksm(g[i-1][j-1], P - 2) % P;
}
int main() {
Prepare();
int T, x, y; scanf("%d", &T);
while (T--) {
scanf("%d%d", &x, &y);
printf("%lld\n", g[x][y]);
}
return 0;
}
想不到正解主要是因爲我對莫比烏斯反演掌握的不好。
翻譯以下題意,題目讓我們求的是,其中F是斐波那契數列,,共有T組數據。
題解:
我們先使得n<=m
然後我們把右上角這一大坨東西提取出來
所以
越是我們設T=kd,然後將T提取出來,得到
令
則
然後發現外層可以用數論分塊來做,也就是從i到n/(n/i)的n/i之都是相等的
有了這個,我們就要求數組的前綴的乘積。
那麼數組怎麼求呢,設求出每一個i,然後對於每一個i的倍數,有即可
參考代碼
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL N = 1e6 + 6, M = 8e4 + 6, P = 1e9 + 7;
int ksm(int a, LL b) { //快速冪
if (b < 0) b += P - 1; //因爲莫比烏斯函數有負數,所以我們要對負數進行特殊處理
int ans = 1;
for (; b; a = (LL)a * a % P, b >>= 1)
if (b & 1) ans = (LL)ans * a % P;
return ans;
}
bool v[N];
int pr, prime[M], miu[N], f[N], inv[N];
//pr和prime表示質數,miu即爲μ,f表示f數組的前綴乘積,inv表示f的乘法逆元
void init() {
v[1] = 1, miu[1] = 1;
for (int i = 2; i <= 1000000; i++) {//線性篩求μ函數
if (!v[i]) prime[++pr] = i, miu[i] = -1;
for (int j = 1, k; j <= pr && (LL)i * prime[j] <= 1000000; j++) {
k = prime[j] * i;
v[k] = 1;
if (i % prime[j]) miu[k] = -miu[i];
else break;
}
}
for (int i = 1; i <= 1000000; i++)
f[i] = 1, inv[i] = 1;
int l = 1, r = 0;//l和r表示斐波那契數列
for (int i = 1; i <= 1000000; i++) {
r = (l + r) % P;
l = (r - l + P) % P;
int c[3] = {ksm(r, -1), 1, r};//求f數組
for (int j = i, k = 1; j <= 1000000; j += i, k++) {
f[j] = (LL)f[j] * c[miu[k] + 1] % P;
inv[j] = (LL)inv[j] * c[1 - miu[k]] % P;
}
}
f[0] = inv[0] = 1;//求f數組的前綴乘積
for (int i = 1; i <= 1000000; i++) {
f[i] = (LL)f[i - 1] * f[i] % P;
inv[i] = (LL)inv[i-1] * inv[i] % P;
}
}
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 ans = 1;
for (int i = 1, j; i <= n; i = j + 1) {
j = min(n / (n / i), m / (m / i));//數論分塊
ans = (LL)ans * ksm((LL)f[j] * inv[i-1] % P, (LL)(n / i) * (m / i)) % P;
}
printf("%d\n", ans);
}
return 0;
}