2020.1.17 小测

总结 link

已知 \(f(x) = \displaystyle \sum_{d|x}μ(d)∗d\)

现在请求出下面式子的值

\(\displaystyle \sum_{i=1}^n \sum_{j=1}^nf(gcd(i,j))∗f(lcm(i,j))\)

由于值可能过大所以请对 10^9+7 取模

\(n≤10^9\)

输入

一行一个整数 n

输出

一行一个数字,为问题描述所求的值

输入样例

4

输出样例

9

正解

看到 gcd 与 lcm 就想乘起来 , 得到 i * j , 考试时我也这么做了 , 结果也没写出来 。

考完之后听老师讲 , 才发现 f 不是完全积性函数 , 而 gcd 与 lcm 也不互质 , 心里一阵发慌。。。。。。

不过吧 , 正解就是 \(f(gcd(i , j)) * f(lcm(i , j)) = f(ij)\) 原因吧。。

把 i , j 质因数分解, 没有的就当成 0 次幂 。

gcd 就相当于 , 两者的指数取min , lcm 就相当于取 max , 设 两个指数分别是 c1 , c2;

\(p^{c1} * p^{c2} = p^{max(c1 , c2) + min(c1 , c2)}\) 瞎猫碰见了死耗子。。。。。。

这样就是 \(ans = \displaystyle {\sum_{i=1}^nf(i)}^2\)
\[ \large{ \begin{aligned} ans =& \sum_{i=1}^n\sum_{j|i}j * \mu(j) \\ =&\sum_{d=1}^n\sum_{i=1}^{n/d}d * \mu(d)\\ =&\sum_{d=1}^nd * \mu(d) * (n/d) \\ \end{aligned} } \]
(n / d) 可以整除分块 , 之后就是计算\(d * \mu(d)\) 的前缀和

\(g(x) = x * \mu(x)\)
\[ \large{ \begin{aligned} (g * id)(x) &= \sum_{d|x}d * \mu(d) * (n/d) \\ &= \sum_{d|x}\mu(d) \\ &= e \end{aligned} } \]
很神奇吧 , 之后就是杜教筛的板子了 , 放代码

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
const int mod = 1e9+7 , N = 2e6 + 100 , maxn = 2e6;
#define int long long
int n , tot;
map<int,int> w;
int prime[N] , vis[N] , mu[N] , f[N];
void Init(int maxn)
{
    mu[1] = 1;
    for(int i = 2 ; i <= maxn ; ++i)
    {
        if(!vis[i]) prime[++tot] = i , mu[i] = -1;
        for(int j = 1 ; j <= tot && i * prime[j] <= maxn ; ++j)
        {
            vis[i * prime[j]] = 1;
            if(i % prime[j] == 0)
            {
                mu[i * prime[j]] = 0;
                break;
            }
            mu[i * prime[j]] = -mu[i];
        }
    }
    for(int i = 1 ; i <= maxn ; ++i) f[i] = (f[i-1] + mu[i] * i % mod) % mod;
    return ;
}

int get(int n)
{
    if(n <= maxn) return f[n];
    if(w.count(n)) return w[n];
    int res = 0;
    for(int i = 2 , r ; i <= n ; i = r + 1)
    {
        r = min(n , n / (n / i));
        res = (res + get(n / i) * ((i + r) * (r - i + 1) / 2) % mod) % mod;
    }
    res = ((1 - res) % mod + mod) % mod;
    return w[n] = res;
}

signed main()
{
    freopen("A.in" , "r" , stdin);
    freopen("A.out" , "w" , stdout);
    cin >> n; Init(2e6);
    int ans = 0;
    for(int i = 1 , r; i <= n ; i = r + 1)
    {
        r = min(n , n / (n / i));
        ans = (ans + (get(r) - get(i-1) + mod) % mod * (n / i) % mod) % mod;
    }
    cout << ans * ans % mod << endl;
    fclose(stdin); fclose(stdout); return 0;
}

猜你喜欢

转载自www.cnblogs.com/R-Q-R-Q/p/12207401.html
今日推荐