标签:约数 描述 分块 cci 数据 span getch stream 学习
[BZOJ4816][Sdoi2017]数字表格
试题描述
输入
有多组测试数据。
输出
输入示例
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;
}
标签:约数 描述 分块 cci 数据 span getch stream 学习
原文地址:http://www.cnblogs.com/xiao-ju-ruo-xjr/p/7109941.html