题意:
已知x和n,求
∑gcd(xa−1,xb−1)(1≤a,b≤n)
思路
记
T(t)=1+x+x2+...+xt−1
xa−1=(x−1)(1+x+x2+...+xa−1)=(x−1)∗T(a)
则
gcd(xa−1,xb−1)=(x−1)∗gcd(T(a),T(b))
有公式:
gcd(T(t1),T(t2))=T(gcd(t1,t2))
所以
gcd(xa−1,xb−1)=(x−1)∗T(gcd(a,b))=xgcd(a,b)−1
∑gcd(xa−1,xb−1)=∑(xgcd(a,b)−1)=−n2+∑xgcd(a,b)
(a,b)的种数在
n2
级,但gcd(a,b)的种数在
n
级,假设
∑xgcd(a,b)(1≤a,b≤n)=∑xif(n/i)(1≤i≤n)
f(i)
很容易由
phi
函数得到,所以整个可以在
O(n)
时间内计算出来,这样T组数据复杂度为
O(Tn)
的,需要优化。
由于
∑xif(n/i)
中
n/i
的种数在
O(n−−√)
级,所以可以分段计算
∑xif(n/i)(1≤i≤n)=∑(xlt+xlt+1+...+xrt)f(t)(t是n/i取得的所有可能的值)
对每个t可以
o(1)
算出来,但等比数列求和需要求逆元花费
O(logn)
时间,所以这一步复杂度为
O((√n)logn)
,加上前面的各种预处理总复杂度为
O(n+Tn−−√logn)
对分段方法的说明:
假定当前计算到了i,则需要求出最大的j使得:
⌊n/i⌋=⌊n/j⌋
,有一个公式是:
j=⌊n/⌊n/i⌋⌋)
证明如下
令
n=pi+q
,则
⌊n/i⌋=⌊n/j⌋=p
———A
⌊n/(j+1)⌋<p
———B
由A得
⌊(pi+q)/j⌋=p
,所以
pi+q≥pj
———-C
由B得
⌊(pi+q)/(j+1)⌋<p
,所以
pi+q<p(j+1)
———D
综合C、D得
i+q/p−1<j≤i+q/p
由于左右边界刚好相差1,所以区间内刚好有1个整数,即
j=i+⌊q/p⌋
i+⌊q/p⌋=i+⌊(n−pi)/p⌋=i+⌊n/p⌋−i=⌊n/p⌋=⌊n/⌊n/i⌋⌋
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int N = 1e6 + 7;
typedef long long ll;
int phi[N], f[N], g[N], x, n, _, sqrtn, ans, l, r;
void init() {
for (int i = 1; i < N; i++) phi[i] = i;
for (int i = 2; i < N; i++) {
if (phi[i] == i) {
for (int j = i; j < N; j += i) {
phi[j] = phi[j] / i * (i - 1);
}
}
}
for (int i = 1; i < N; i++) {
f[i] = (f[i - 1] + phi[i]) % mod;
g[i] = (2ll * f[i] - 1 + mod) % mod;
}
}
ll powermod(ll a, ll n, ll mod) {
ll ans = 1;
while (n) {
if (n & 1) ans = ans * a % mod;
a = a * a % mod;
n >>= 1;
}
return ans;
}
ll F(ll l, ll r) {
if (x == 1) return r - l + 1;
return (powermod(x, r + 1, mod) - powermod(x, l, mod) + mod) % mod * powermod(x - 1, mod - 2, mod) % mod;
}
int main() {
init();
cin >> _;
while (_--) {
cin >> x >> n;
ans = 0;
l = r = 1;
for (; l <= n; l = r + 1) {
r = n / (n / l);
ans = (ans + g[n / l] * F(l, r) % mod) % mod;
}
cout << (ans - (ll)n * n % mod + mod) % mod << endl;
}
return 0;
}