链接(不知何时失效)
1008: 欧拉函数求和
Description
前不久,小D刚刚学习了欧拉函数.
[1,n] 中和n 互素的个数称为nn的欧拉函数,记作ϕ(n)。其中,有一个性让它记忆深刻:n的所有因子的欧拉函数之和等于n,即 ∑d∣n ϕ(d)=n但是, 他并没有停下探索的脚步,经过一番脑洞后,他构造出了个更一般的函数: f(n,k)=∑ik∣ik−1∣⋯∣i1∣n ϕ(ik), 其,a|b 代表a整除b,即a是b的因子。ij(1≤j≤k)是正整数。也就说,对于每个满足上述条件的合法序列(ik,ik−1,…,i1),对ik的欧拉函值求和。举例:f(4,2)=∑i2∣i1∣4 的合法序分别为(1,1),(1,2),(1,4),(2,2),(2,4),(4,4),f(4,2)=ϕ(1)∗3+ϕ(2)∗2+ϕ(4)∗1=7。这可难倒了小,他想让大家帮忙求出这个式子的答案。
Input第一行输入数据组数(1≤t≤1000)(1≤t≤1000), 第二行依次输入两个整数nn和k(1≤n,k≤100000)(1≤n,k≤100000)。
Output对于每组数据输出一行f(n,k)mod1000000007f(n,k)mod1000000007。Sample Input
3
5 1
10 2
30 3
Sample Output
5
18
140
分析:
自己学校出的题。
这道题解法比较多,我用狄利克雷卷积的方法做的。
首先式子可以改写成
f(n,k)=φ(n)∗g(n)∗g(n)∗...∗∗g(n)
那么只要对n质因子分解,然后改成
f(pαii,k)
,对每个质因子求一次卷积就行了。乘方可以用快速幂来解决。
复杂度:
O(α2i×logk)
代码:
/*****************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define offcin ios::sync_with_stdio(false)
#define sigma_size 26
#define lson l,m,v<<1
#define rson m+1,r,v<<1|1
#define slch v<<1
#define srch v<<1|1
#define sgetmid int m = (l+r)>>1
#define ll long long
#define ull unsigned long long
#define lowbit(x) (x&-x)
#define bits(a) __builtin_popcount(a)
const int INF = 0x3f3f3f3f;
const ll INFF = 1e18;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-9;
const ll mod = 1e9+7;
const int maxmat = 10;
const ull BASE = 133333331;
/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/
const int maxn = 1e5 + 5;
ll f[30], g[30], t[30];
void dirichlet(ll *a, ll *b, ll *c, int len) {
for (int i = 0; i <= len; i ++) c[i] = 0;
for (int i = 0; i <= len; i ++)
for (int j = 0; j <= i; j ++)
c[i] = (c[i] + a[j] * b[i - j] % mod) % mod;
for (int i = 0; i <= len; i ++) a[i] = c[i];
}
void qpow(ll *a, ll *b, ll len, int k) {
for (int i = 0; i <= len; i ++) b[i] = 1;
for (int i = 0; i <= len; i ++) a[i] = 0; a[0] = 1;
while (k) {
if (k & 1) dirichlet(a, b, t, len);
k >>= 1; dirichlet(b, b, t, len);
}
for (int i = 0; i <= len; i ++) b[i] = a[i];
}
ll work(int p, int cnt, int k) {
qpow(f, g, cnt, k);
for (int i = 0; i <= cnt; i ++) f[i] = 0;
f[0] = 1; ll ans = 0;
for (int i = 0; i <= cnt; i ++) {
ans = (ans + f[i] * g[cnt - i] % mod) % mod;
if (!i) f[i + 1] = f[i] * (p - 1) % mod;
else f[i + 1] = f[i] * p % mod;
}
return ans;
}
int main(int argc, char const *argv[]) {
int T; cin>>T;
while (T --) {
int N, K;
scanf("%d%d", &N, &K);
ll ans = 1;
for (int i = 2; (ll)i * i <= N; i ++) {
if (N % i == 0) {
int cnt = 0;
while (N % i == 0) N /= i, cnt ++;
ans = ans * work(i, cnt, K) % mod;
}
}
if (N > 1) ans = ans * work(N, 1, K) % mod;
printf("%lld\n", ans);
}
return 0;
}