题意
求组
数据范围:
题解
首先
其次一定是的约数,我们枚举的值
在gcd中我介绍过一种对于的求法,也是枚举的值
对于每个,,那么
这题运用同样的思想:
这里涉及如何对比小且与互素的元素求和的子问题
我们注意到若,对于,故可是配对求和得;和也为
整理一下答案即为(我们可以特别的记或者单列出来考虑的情况,下面的操作是后者)
直接计算会,需要进一步化解
考虑的素因子分解,注意到每个对于求和的贡献是相对独立的
我们分析任意:
- 不含,对其贡献为
- ,贡献为
- 所以总共献为
- 那么
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
using LL = long long;
const int MOD = 1e9 + 7;
const int MAXN = 4e4 + 5;
int T, N;
bool noprime[MAXN];
int prime[MAXN], cnt_p;
void Euler_Sieve(int top);
LL qpow(LL, LL);
int main(){
ios::sync_with_stdio(false);
Euler_Sieve(MAXN - 5);
int inv_2 = MOD / 2 + 1;
cin >> T;
while(T--){
cin >> N;
LL ans = N, tmp = 1;
int i;
for(i = 1; i <= cnt_p && N >= prime[i]; i++)
if(N % prime[i] == 0){
int ind = 0;
while(N % prime[i] == 0) N /= prime[i], ind++;
tmp = tmp * (1 + prime[i] * (qpow(prime[i], 2 * ind) - 1 + MOD) % MOD * qpow(prime[i] + 1, MOD - 2) % MOD) % MOD;
}
if(N > 1) tmp = tmp * (1 + 1LL * N * (N - 1 + MOD) % MOD) % MOD;
tmp += 1;
ans = ans * tmp % MOD;
ans = ans * inv_2 % MOD;
cout << ans << endl;
}
return 0;
}
LL qpow(LL x, LL n){
LL res = 1;
while(n){
if(n & 1) res = res * x % MOD;
x = x * x % MOD;
n >>= 1;
}
return res;
}
void Euler_Sieve(int top){
int i, j;
for(i = 2; i <= top; i++){
if(!noprime[i]) prime[++cnt_p] = i;
for(j = 1; j <= cnt_p && prime[j] * i <= top; j++){
noprime[prime[j] * i] = true;
if(i % prime[j] == 0){
break;
}
}
}
}