13512:DZY Loves Math IV

#include <bits/stdc++.h>
 
#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define pb push_back
 
using namespace std;
 
template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }
 
inline int read() {
    int x(0), sgn(1); char ch(getchar());
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
    for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
    return x * sgn;
}
 
void File() {
#ifdef zjp_shadow
    freopen ("3512.in", "r", stdin);
    freopen ("3512.out", "w", stdout);
#endif
}
 
const int Lim = 1e5, N = Lim + 1e3, Mod = 1e9 + 7;
 
int prime[N], pcnt, phi[N], sumphi[N], minp[N];
bitset<N> is_prime;
 
void Linear_Sieve(int maxn) {
    is_prime.set(); is_prime[0] = is_prime[1] = false;
    phi[1] = sumphi[1] = 1;
    For (i, 2, maxn) {
        if (is_prime[i]) prime[++ pcnt] = i, phi[i] = i - 1, minp[i] = i;
        for (int j = 1, res; (res = i * prime[j]) <= maxn && j <= pcnt; ++ j) {
            is_prime[res] = false; minp[res] = prime[j];
            if (i % prime[j]) phi[res] = phi[i] * (prime[j] - 1);
            else { phi[res] = phi[i] * prime[j]; break; }
        }
        sumphi[i] = (sumphi[i - 1] + phi[i]) % Mod;
    }
}
 
map<int, int> M, val[N];
 
#define Out(a, b) if (a) return b;
 
int Phi(int n) {
    Out(n <= Lim, sumphi[n]); Out(M[n], M[n]);
    int res = 1ll * n * (n + 1) / 2 % Mod;
    for (int i = 2, ni; i <= n; i = ni + 1)
        res = (res + Mod - ((ni = n / (n / i)) - i + 1ll) * Phi(n / i)) % Mod;
    return M[n] = res;
}
 
int S(int n, int m) {
    Out(!m, 0); Out(n == 1, Phi(m)); Out(m == 1, phi[n]); Out(val[n][m], val[n][m]);
    int res = 0, p = 1, q = 1, tmp = n; vector<int> fac;
    while (tmp > 1) {
        int x = minp[tmp]; q *= x; tmp /= x; fac.pb(x);
        while (!(tmp % x)) p *= x, tmp /= x;
    }
    Rep (i, 1 << int(fac.size())) {
        int d = 1;
        Rep (j, fac.size()) if (i >> j & 1) d *= fac[j];
        res = (res + 1ll * phi[q / d] * S(d, m / d)) % Mod;
    }
    return val[n][m] = 1ll * res * p % Mod;
}
 
int main () {
 
    File();
 
    Linear_Sieve(Lim);
 
    int n = read(), m = read(), ans = 0;
    For (i, 1, n) 
        ans = (ans + S(i, m)) % Mod;
    printf ("%d\n", ans);
 
    return 0;
 
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值