[BZOJ4816][Sdoi2017]数字表格
[BZOJ4816][Sdoi2017]数字表格
试题描述
Doris刚刚学习了fibonacci数列。用f[i]表示数列的第i项,那么
f[0]=0
f[1]=1
f[n]=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
数据规模及约定
见“输入”
题解
要求这么个东西

考虑枚举 gcd(i, j)

于是分块套分块,好像能卡过。。。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
#define maxn 1000010
#define maxt 2828
#define MOD 1000000007
#define LL long long
void gcd(LL a, LL b, LL& x, LL& y) {
if(!b){ x = 1; y = 0; return ; }
gcd(b, a % b, y, x); y -= a / b * x;
return ;
}
int inv(LL a) {
LL x, y;
gcd(a, MOD, x, y);
return (x % MOD + MOD) % MOD;
}
int prime[maxn], cp, mu[maxn], smu[maxn], f[maxn], tf[maxn], invt[maxn];
bool vis[maxn];
void init() {
mu[1] = 1; smu[1] = 1;
for(int i = 2; i < maxn; i++) {
if(!vis[i]) prime[++cp] = i, mu[i] = -1;
for(int j = 1; i * prime[j] < maxn && j <= cp; j++) {
vis[i*prime[j]] = 1;
if(i % prime[j] == 0){ mu[i*prime[j]] = 0; break; }
mu[i*prime[j]] = -mu[i];
}
smu[i] = smu[i-1] + mu[i];
}
int f1 = 0, f2 = 1; tf[1] = invt[1] = 1; invt[0] = 1;
for(int i = 2; i < maxn; i++) {
swap(f1, f2); f2 += f1; if(f2 >= MOD) f2 -= MOD;
tf[i] = (LL)tf[i-1] * f2 % MOD;
invt[i] = inv(tf[i]);
}
return ;
}
LL get[maxt][maxt];
LL g(int n, int m) {
if(n < maxt && m < maxt) {
LL& ans = get[n][m];
if(ans) return ans;
for(int i = 1, lst; i <= n; i = lst + 1) {
lst = min(n / (n / i), m / (m / i));
ans += (LL)(n / i) * (m / i) * (smu[lst] - smu[i-1]);
}
return ans;
}
LL ans = 0;
for(int i = 1, lst; i <= n; i = lst + 1) {
lst = min(n / (n / i), m / (m / i));
ans += (LL)(n / i) * (m / i) * (smu[lst] - smu[i-1]);
}
return ans;
}
int Pow(int a, LL b) {
int t = a, ans = 1;
while(b) {
if(b & 1) ans = (LL)ans * t % MOD;
t = (LL)t * t % MOD; b >>= 1;
}
return ans;
}
int main() {
init();
int T = read();
while(T--) {
int n = read(), m = read(), ans = 1;
if(n > m) swap(n, m);
for(int i = 1, lst; i <= n; i = lst + 1) {
lst = min(n / (n / i), m / (m / i));
ans = (LL)ans * Pow((LL)tf[lst] * invt[i-1] % MOD, g(n / i, m / i)) % MOD;
}
printf("%d\n", ans);
}
return 0;
}

浙公网安备 33010602011771号