题目描述
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5780
题目大意:
求 ∑na=1∑nb=1(xa−1,xb−1),1≤x,n≤1000000,T≤300 。
思路
这是一道数论小水题,但也不是我这个zz想得出来的。主要是这题用到了一个很神的结论:
(xa−1,xb−1)=x(a,b)−1
看上去炒鸡厉害,有木有?
下面简单证明一下:
假设
a>b
,更相减损,有
(xa−1,xb−1)=(xa−xb,xb−1)=(xb(xa−b−1),xb−1)
注意到 xb 和 xb−1 互质,故化成
(xa−b−1,xb−1)
然后我们发现这是在对指数更相减损,当其中一个指数变为0时,另一个指数就是 (a,b) ,故 (xa−1,xb−1)=x(a,b)−1 ,证毕。
知道这个结论后,开始画柿子
∑i=1n∑j=1nx(i,j)−1
=∑d=1n(xd−1)∑i=1⌊nd⌋∑j=1⌊nd⌋[(i,j)=1]
明显
1..n
中互质的有序数对有
2∑ni=1φ(i)−1
个,于是答案就是
∑d=1n(xd−1)(2∑i=1⌊nd⌋φ(i)−1)
直接大力分块即可,等比数列求和别忘了特判公比为1的情况。
代码
#include <bits/stdc++.h>
#define MOD 1000000007
#define maxn 1000010
#define temp (i * prime[j])
using namespace std;
typedef long long LL;
int T;
int x, n, cnt;
int prime[maxn];
LL phi[maxn], ans;
bool Vis[maxn];
void Da(){
phi[1] = 1LL;
for(int i = 2; i < maxn; i++){
if(!Vis[i]){
prime[++cnt] = i;
phi[i] = (LL)i - 1LL;
}
for(int j = 1; j <= cnt && temp < maxn; j++){
Vis[temp] = true;
if(i % prime[j] == 0){
phi[temp] = phi[i] * prime[j] % MOD;
break;
}
else phi[temp] = phi[i] * (prime[j] - 1) % MOD;
}
}
for(int i = 2; i < maxn; i++) phi[i] = (phi[i] + phi[i-1]) % MOD;
}
LL Pow(int a, int b){
LL res = 1LL;
for(; b; a = 1LL * a * a % MOD, b >>= 1)
if(b & 1) res = res * a % MOD;
return res;
}
LL Sum(int st, int ed){
if(x == 1) return 0LL;
LL temp1 = Pow(x, st) * ((1LL - Pow(x, ed-st+1) + MOD) % MOD) % MOD;
LL temp2 = Pow(1-x+MOD, MOD-2);
return (temp1 * temp2 % MOD - (ed-st+1) + MOD) % MOD;
}
int main(){
Da();
scanf("%d", &T);
while(T --){
scanf("%d%d", &x, &n);
ans = 0LL;
int last;
for(int i = 1; i <= n; i = last+1){
last = n/(n/i);
ans = (ans + (phi[n/i] * 2 - 1LL) % MOD * Sum(i, last) % MOD) % MOD;
}
printf("%lld\n", ans);
}
return 0;
}