HDU 5407
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5407
题意:
,求g(n)
思路:
首先有一个公式,设,,则。公式证明很复杂也没看懂也不想看,好像都是上数列网和打表找规律过的。
那么现在我们有f(n+1)了,要求f(n+1)/(n+1) %(1e9+7),需要用费马小定理来求带模除法的逆元。
原理
对m是素数且m不能整除b的b,有b^(m - 1) = 1 mod (m) 证明可见扩展欧几里得
则 (a / b) % m
= (a / b * b ^ (m - 1) ) % m
= (a * b^(m - 2)) % m
完。
源码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
#define LL long long
#define MOD (1000000007)
const int MAXN = 1e6 + 5;
int prime[MAXN], vis[MAXN], val[MAXN];
LL LCM[MAXN];
void init()
{
int cnt = 0;
memset(vis, 0, sizeof(vis));
for(int i = 2 ; i < MAXN ; i++){
if(vis[i] == 0){
prime[cnt++] = i;
int now = i;
while(now < MAXN){
vis[now] = 1;
now += i;
}
}
}
for(int i = 1 ; i < MAXN ; i++)
val[i] = 1;
for(int i = 0 ; i < cnt ; i++){
LL temp = prime[i];
while(temp < MAXN){
val[temp] = prime[i];
temp *= prime[i];
}
}
LCM[1] = 1;
for(int i = 2 ; i < MAXN ; i++)
LCM[i] = (LCM[i - 1] * val[i]) % MOD;
}
LL ppow(LL a, int b, LL m)
{
LL temp = 1;
while(b){
if(b & 1)
temp = (temp * a) % m;
a = (a * a) % m;
b >>= 1;
}
return temp;
}
LL cal(int mark)
{
LL temp = mark;
temp = ppow(temp, MOD - 2, MOD);
// printf("LCM = %I64d, temp = %I64d\n", LCM[mark], temp);
LL ans = (LCM[mark] * temp) % (LL)MOD;
return ans;
}
int main()
{
init();
int t;
scanf("%d", &t);
while(t--){
int n;
scanf("%d", &n);
LL ans = cal(n + 1);
printf("%I64d\n", ans % MOD);
}
return 0;
}