dlutoj 1008 欧拉函数求和

链接(不知何时失效)
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值