传送门:SPOJ -NUMTRYE
题解:
- 首先
∑ni=1gcd(n,i)=∑d|ndϕ(nd)
所以 g(n)=∑ni=1n/gcd(n,i)=∑d|nndϕ(nd)=∑d|ndϕ(d) - 根据欧拉函数定义和欧拉函数性质的证明过程:http://blog.csdn.net/adjky/article/details/61198817
枚举n的因子利用欧拉函数积性可得:
设 n=pe11pe22⋅⋅⋅pekk
那么
设d|n,d=pa11pa22⋅⋅⋅pakk所以ϕ(d)=∏ki=1paii−pai−1i
那么d∗ϕ(d)=∏ki=1p2aii−p2ai−1i
因此:
g(n)=∑d|ndϕ(d)=∏i=1k∑j=0eiϕ(pji)=∏i=1k(1+∑j=1eip2ji−p2j−1i)=∏i=1kp2ei+1i+1pi+1
所以 f(n)/g(n)=∏ki=1(pi+1)
分解质因子即可:
注意最多有10000个cas所以要先处理1e6以内的质因子优化分解:
code:
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const ll p = 1e9 + 7;
ll n;
bool vis[1000010];
ll prime[1000010];
int cnt = 0;
void getPrime(){
memset(vis, 0, sizeof vis);
for(int i = 2; i <= 1000000; ++i){
if(!vis[i]) prime[++cnt] = i;
for(int j = 1; j <= cnt && prime[j] * i <= 1000000; ++j){
vis[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
}
}
}
ll solve(){
ll res = 1;
for(int i = 1; i <= cnt && prime[i] * prime[i] <= n; ++i){
if(n % prime[i] == 0){
while(n % prime[i] == 0){
n /= prime[i];
}
res = res * (prime[i] + 1) % p;
}
}
if(n > 1) res = res * (n + 1) % p;
return res;
}
int main(){
getPrime();
int t;
cin >> t;
while(t--){
cin >> n;
cout << solve() << endl;
}
return 0;
}
总结:
遇到这类推到题, 优先考虑熟悉的形式转化