码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj3994] [SDOI2015] 约数个数和

时间:2019-03-15 23:18:32      阅读:289      评论:0      收藏:0      [点我收藏+]

标签:cpp   ==   main   --   莫比乌斯反演   表示   tput   \n   代码   

Description

\(d(x)\)\(x\) 的约数个数,给定 \(N\)\(M\),求 \(\sum\limits_{i=1}^N \sum\limits_{j=1}^M d(ij)\)

Input

输入文件包含多组测试数据。
第一行,一个整数 \(T\) ,表示测试数据的组数。
接下来的 \(T\) 行,每行两个整数 \(N\)\(M\)

Output

\(T\) 行,每行一个整数,表示你所求的答案。

Sample Input

2

7 4

5 6

Sample Output

110

121

HINT

\(1<=N, M<=50000\)
\(1<=T<=50000\)


想法

首先有一个结论
$ d(i,j)=\sum\limits_{x|i} \sum\limits_{y|j} [gcd(x,y)==1] $
原谅我不会证 \(qwq\)

接下来,喜闻乐见的推式子
\[ \begin{equation*} \begin{aligned} &\sum\limits_{i=1}^n \sum\limits_{j=1}^m d(ij) \=&\sum\limits_{i=1}^n \sum\limits_{j=1}^m \sum\limits_{x|i} \sum\limits_{y|j} [gcd(x,y)==1] \=&\sum\limits_{i=1}^n \sum\limits_{j=1}^m [gcd(x,y)==1] \times \lfloor \frac{n}{x} \rfloor \times \lfloor \frac{m}{y} \rfloor \\end{aligned} \end{equation*} \]
\(f(i)=\sum\limits_{i=1}^n \sum\limits_{j=1}^m [gcd(x,y)==1] \times \lfloor \frac{n}{x} \rfloor \times \lfloor \frac{m}{y} \rfloor\)
应用莫比乌斯反演
\[ \begin{equation*} \begin{aligned} F(i)&=f(i)+f(2i)+... \&=\sum\limits_{x=1}^{\lfloor \frac{n}{i} \rfloor} \sum\limits_{y=1}^{\lfloor \frac{m}{i} \rfloor} \lfloor \frac{n}{ix} \rfloor \lfloor \frac{m}{iy} \rfloor \&=\sum\limits_{x=1}^{\lfloor \frac{n}{i} \rfloor} \lfloor \frac{n}{ix} \rfloor \sum\limits_{y=1}^{\lfloor \frac{m}{i} \rfloor} \lfloor \frac{m}{iy} \rfloor \end{aligned} \end{equation*} \]
不妨设 \(s(x)=\sum\limits_{i=1}^x \lfloor \frac{x}{i} \rfloor\)
它可以预处理后 \(O(1)\) 调用
\(f(i)=\sum\limits_{i|d} \mu(\frac{d}{i}) s(\frac{n}{d}) s(\frac{m}{d})\)
那么
\[ \begin{equation*} \begin{aligned} ans&=f(1) \&=\sum\limits_{i=1}^{min(n,m)} \mu(i) s(\frac{n}{i})s(\frac{m}{i}) \end{aligned} \end{equation*} \]
然后就好啦。


代码

#include<cstdio>
#include<iostream>
#include<algorithm>
 
using namespace std;
 
const int N = 50005;
typedef long long ll;
 
ll s[N];
int mu[N],p[N],prime[N],pnum,sum[N];
void getp(){
    mu[1]=sum[1]=1;
    for(int i=2;i<N;i++) p[i]=1;
    for(int i=2;i<N;i++){
        if(p[i]) prime[pnum++]=i,mu[i]=-1;
        for(int j=0;j<pnum && (ll)prime[j]*i<N;j++){
            p[i*prime[j]]=0;
            if(i%prime[j]==0){
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
        sum[i]=sum[i-1]+mu[i];
    }
}
void gets(){
    for(int x=1;x<N;x++){
        for(int l=1,r;l<=x;l=r+1){
            r=x/(x/l);
            s[x]+=1ll*(x/l)*(r-l+1);
        }
    }
}
 
int main()
{
    int T,n,m;
    getp(); gets();
     
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        ll ans=0;
        for(int l=1,r;l<=n && l<=m;l=r+1){
            r=min(n/(n/l),m/(m/l));
            ans+=s[n/l]*s[m/l]*(sum[r]-sum[l-1]);
        }
        printf("%lld\n",ans);
    }
     
    return 0;
}
?

[bzoj3994] [SDOI2015] 约数个数和

标签:cpp   ==   main   --   莫比乌斯反演   表示   tput   \n   代码   

原文地址:https://www.cnblogs.com/lindalee/p/10539858.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!