51nod 1220 约数之和

约数之和

Problem

d(k)表示k的所有约数的和。d(6) = 1 + 2 + 3 + 6 = 12。

定义S(N) = ∑1<=i<=N ∑1<=j<=N d(i*j)。

例如:S(3) = d(1) + d(2) + d(3) + d(2) + d(4) + d(6) + d(3) + d(6) + d(9) = 59,S(1000) = 563576517282。

给出正整数N,求S(N),由于结果可能会很大,输出Mod 1000000007(10^9 + 7)的结果。

输入

输入一个数N(2 <= N <= 10^9)。

输出

输出S(N) Mod 1000000007(10^9 + 7)的结果。

输入样例

1000

输出样例

576513341

Guess

首先得会把\(d(ij)\) 写成\(\gcd\) 的形式

然后搞一波莫比乌斯变换

再用和式化一化

上个杜教筛,打个分块

好像就能解决了!

Solve

就是推公式呗。

这里这个\(d(ij)\) 与之前的不太一样,这里是约数之和的函数。

必须要知道这个式子才可以往后推:

\[d(ij)=\sum\limits_{x|i}\sum\limits_{y|j}[\gcd(x,y)==1]x\cdot\frac{j}{y}\]

(意会一下这个式子,大概和之前的除数函数相类似,枚举质因子分析的感觉)
(我不懂怎么来的)

这样的话

\[
\begin{align}
S(n) &= \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}d(ij)\ &= \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{x|i}\sum\limits_{y|j}[\gcd(x,y)==1]x\cdot\frac{j}{y}\ & 来一波莫比乌斯变换吧!\ &=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{x|i}\sum\limits_{y|j}\sum\limits_{d|\gcd(x,y)}\mu (d)\cdot x\cdot\frac{j}{y}\ &=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{x|i}\sum\limits_{y|j}\sum\limits_{d=1}^n\mu (d)[d|\gcd(x,y)]\cdot x\cdot\frac{j}{y}\ &我们知道d|\gcd(x,y)=d|x 且d|y \&=\sum\limits_{d=1}^n\mu (d)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{x|i}\sum\limits_{y|j}[d|x][d|y]\cdot x\cdot\frac{j}{y}\&对于枚举1到n的数i的因子x的因子d\&其实就是枚举1到n的因子d的倍数x的倍数i\&=\sum\limits_{d=1}^n\mu (d)\sum\limits_{d|x}\sum\limits_{d|y}\frac{x}{y}\sum\limits_{x|i}\sum\limits_{y|j}j\&这里的\sum\limits_{y|j}j=y+2y+3y+\cdots+\lfloor\frac{n}{y}\rfloor y\&=\sum\limits_{d=1}^n\mu (d)\sum\limits_{d|x}\sum\limits_{d|y}\frac{x}{y}\lfloor\frac{n}{x}\rfloor\cdot y \frac{\lfloor\frac{n}{y}\rfloor(\lfloor\frac{n}{y}\rfloor+1)}{2} \&=\sum\limits_{d=1}^n\mu (d)\sum\limits_{d|x}x\lfloor\frac{n}{x}\rfloor\sum\limits_{d|y}\frac{\lfloor\frac{n}{y}\rfloor(\lfloor\frac{n}{y}\rfloor+1)}{2} \&=\sum\limits_{d=1}^n\mu (d)\sum\limits_{x=1}^{\lfloor\frac{n}{d}\rfloor}dx\lfloor\frac{n}{dx}\rfloor\sum\limits_{y=1}^{\lfloor\frac{n}{y}\rfloor}\frac{\lfloor\frac{n}{dy}\rfloor(\lfloor\frac{n}{dy}\rfloor+1)}{2} \&=\sum\limits_{d=1}^n\mu (d)d\sum\limits_{x=1}^{\lfloor\frac{n}{d}\rfloor}x\lfloor\frac{n}{dx}\rfloor\sum\limits_{y=1}^{\lfloor\frac{n}{y}\rfloor}\frac{\lfloor\frac{n}{dy}\rfloor(\lfloor\frac{n}{dy}\rfloor+1)}{2} \\end{align}
\]
而对于中间的和号可以看成是\(f(\lfloor\frac{n}{d}\rfloor)\)

\[f(n)=\sum\limits_{x=1}^{n}x\lfloor\frac{n}{x}\rfloor\]

对于后面的和号看成是\(g(\lfloor\frac{n}{d}\rfloor)\)

\[
\begin{align}
g(n)&=\sum\limits_{y=1}^{n}\frac{\lfloor\frac{n}{y}\rfloor(\lfloor\frac{n}{y}\rfloor+1)}{2}\&等差数列前n项和\&=\sum\limits_{y=1}^{n}\sum\limits_{i=1}^{\lfloor\frac{n}{y}\rfloor}i\&=\sum\limits_{y=1}^{n}y\lfloor\frac{n}{y}\rfloor
\end{align}
\]
所以这两个式子是一样的。

\[S(n)=\sum\limits_{d=1}^n\mu (d)\cdot d\cdot (\sum\limits_{x=1}^{\lfloor\frac{n}{d}\rfloor}x\lfloor\frac{n}{dx}\rfloor)^2 \]

这样已经可以写了,但是我用的是这个式子

\[S(n)=\sum\limits_{d=1}^n\mu (d)\cdot d\cdot (\sum\limits_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{i=1}^{\lfloor\frac{n}{dx}\rfloor}i)^2 \]

  1. 后面的就是分块
  2. 前面的用杜教筛(其实就是构造\(h=f*g\))
  3. 外面再套一个分块

补充杜教筛的推导

要求\(A(n)=\sum\limits_{i=1}^ni\cdot \mu(i)\)

我们可以设\(f(i)=i\cdot \mu(i)\)

然后开始构造
\[
\begin{align}
h&=f*g\&=\sum\limits_{d|n}d\cdot \mu(d) \cdot g(n/d)\&可以取g(n/d)=n/d\&=n\sum\limits_{d|n}\mu(d)\&然后我们知道\mu *u=I\&=n[n==1]\&=[n==1]=I
\end{align}
\]
套一下杜教筛的公式
\[A(n)=1-\sum\limits_{i=2}^nd\cdot A(\lfloor\frac{n}{d}\rfloor)\]

Code

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int mod = 1e9 + 7;
const int maxn = 6e6;
const int N = 6e6 + 10;
const int inv2 = (mod+1)/2;

int prime[N];
int vis[N];
int mu[N];
ll sum[N];

void sieve()
{
    int p=0;
    mu[1]=1;
    for(int i=2;i<=maxn;i++){
        if(!vis[i]){
            prime[++p]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=p&&i*prime[j]<=maxn;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)break;
            else mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<=maxn;i++){
        sum[i]=(sum[i-1]+1ll*mu[i]*i)%mod;
    }
}

unordered_map<int, ll> mp;

ll S(int l, int r){
    return (1ll*(1ll*(l+r)%mod*(r-l+1)%mod)%mod*inv2)%mod;
}

ll djs(int n){
    if(n<=maxn)return sum[n];
    if(mp[n])return mp[n];
    ll ans=1+mod;
    for(int l=2,r;l>=0&&l<=n;l=r+1){
        r=n/(n/l);
        ans=(ans-1ll*S(l,r)%mod*djs(n/l)%mod+mod)%mod;
    }
    return mp[n]=ans;
}

ll F(int x){
    ll ans=0;
    for(int l=1,r;l<=x;l=r+1){
        r=x/(x/l);
        ans+=1ll*(r-l+1)*S(1,x/l)%mod;
    }
    return ans%mod;
}

int main()
{
    int n;
    scanf("%d",&n);
    sieve();
    ll ans=0;
    for(int l=1,r;l<=n;l=r+1){
        r=n/(n/l);
        ans=(ans%mod+((djs(r)-djs(l-1))%mod)%mod*(F(n/l)%mod*F(n/l)%mod)%mod)%mod;
        ans=(ans+mod)%mod;
    }
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/tongseli/p/11795918.html

时间: 2024-10-08 03:56:06

51nod 1220 约数之和的相关文章

51nod 1220 约数之和(杜教筛 + 推推推推推公式)

题意 给出\(n(1\leq n \leq 10^9)\),求\(\sum_{i=1}^n\sum_{j=1}^n\sigma(ij)\),其中\(\sigma(n)\)表示\(n\)的约数之和. balabala 交了两道杜教筛的的板子题(51nod 1239, 1244)就看到了这题,然后不会搞,然后看题解看了一天一夜终于彻底搞明白一发A掉了...感觉学到了很多,写个博客整理一下,如有错请指出. 技能需求 数论函数与线性筛 莫比乌斯反演(也可以当成容斥去理解) 狄利克雷卷积 杜教筛 强大的数

数学:求一个数的真约数(因数)的个数及所有约数之和

一. 我们知道,每个自然数(不包括0和1)都有2个以上的因数,因数最少的是质数(也叫素数),质数的因数是1和它本身.非质数的自然数也叫合数,它们都含有3个以上(含3个)的因数. 1.怎样求一个数有多少个因数? 对于一个已知的自然数,要求出它有多少个因数,可用下列方法: 首先将这个已知数分解质因数,将此数化成几个质数幂的连乘形式,然后把这些质数的指数分别加一,再相乘,求出来的积就是我们要的结果. 例如:求360有多少个因数. 因为360分解质因数可表示为:360=2^3×3^2×5,2.3.5的指

(c语法百题20)约数之和

知识点: 求约数的算法 for语句,if语句灵活运用. 内容: 键入一个自然数 ,求这个自然数的所有约数之和 输入说明: 一个整数 输出说明: 一个整数 输入样例: 6 输出样例: 12 1 #include <stdio.h> 2 int main() 3 { 4 int n,s=0,i; 5 scanf("%d",&n); 6 for (i=1;i<=n;i++) 7 { 8 if (n%i==0) 9 { 10 s=s+i; 11 } 12 } 13 p

【动态规划】mr359-最大公约数之和

[题目大意] 选取和不超过S的若干个不同的正整数,使得所有数的约数(不含它本身)之和最大. 输入一个正整数S. 输出最大的约数之和. 样例输入 Sample Input 11 样例输出 Sample Output 9 样例说明 取数字4和6,可以得到最大值(1+2)+(1+2+3)=9. 数据规模对于30%的数据,S≤10: 对于100%的数据,S≤1000. [思路] 水题,普通的01背包问题,唯一需要注意的一点是,1的所有约数之和是0!我一开始就因为1没有单独判断而导致了错误. 1 #inc

POJ1845Sumdiv题解--约数之和

题目链接 https://cn.vjudge.net/problem/POJ-1845 分析 \(POJ\)里的数学题总是这么妙啊 首先有一个结论就是\(A=\prod{ \ {p_i}^{c_i} \ }\),那么\(A\)所有约数之和为\((1+p_1+p_1^2+..+p_1^{c_1}) * (1+p_2+p_2^2+...+p_2^{c_2}) ... (1+p_n +p_n^2 +... + p_n^{c_n})\) 这个好像数学归纳法可证,但是感性理解一下也不难 于是这道题就是求\

19: 约数之和

19 约数之和 作者: 朱星垠 时间限制: 1S 章节: 循环 问题描述 : 输入一个正整数(小于1000),计算这个正整数所有约数的和,并打印输出. 输入说明 : 你的程序需要从标准输入设备(通常为键盘)中读入多组测试数据.每组输入数据由一行组成,每行为一个正整数. 输出说明 : 对每组测试数据,你的程序需要向标准输出文件(通常为启动该程序的文本终端)依次输出一组对应的答案:这个正整数所有约数的和,所有数据前后没有多余的空行,两组数据之间也没有多余的空行. 输入范例 : 1 10 输出范例 :

AcWing - 97 - 约数之和(分治、因数和)

题目链接 ??我们首先要知道怎么来求A的约数之和.首先,把A分解质因数,可得:\(A = q1^{k1}\times q2^{k2} ... \times \ qn^{kn}\) 然后我们用乘法的分配律可得A的因数之和为\(F(A) = (q1^0 + q1^1 + ... + q1^{k1}) \times (q2^0 + q2^1 + ... + q2^{k2})\ ... \times \ (qn^0 + qn^1 + ... + qn^{kn})\) ??那么对于\(A^B\)来说,\(

【51nod1220】约数之和

题目 d(k)表示k的所有约数的和.d(6) = 1 + 2 + 3 + 6 = 12. 定义S(N) = ∑1<=i<=N ∑1<=j<=N d(i*j). 例如:S(3) = d(1) + d(2) + d(3) + d(2) + d(4) + d(6) + d(3) + d(6) + d(9) = 59,S(1000) = 563576517282. 给出正整数N,求S(N),由于结果可能会很大,输出Mod 1000000007(10^9 + 7)的结果. 分析 分开处理每个

51NOD 1110 距离之和最小 V3(中位数 + 技巧)

传送门 X轴上有N个点,每个点除了包括一个位置数据X[i],还包括一个权值W[i].该点到其他点的带权距离 = 实际距离 * 权值.求X轴上一点使它到这N个点的带权距离之和最小,输出这个最小的带权距离之和. Input 第1行:点的数量N.(2 <= N <= 10000) 第2 - N + 1行:每行2个数,中间用空格分隔,分别是点的位置及权值.(-10^5 <= X[i] <= 10^5,1 <= W[i] <= 10^5) Output 输出最小的带权距离之和.