bzoj3994: [SDOI2015]约数个数和(莫比乌斯反演+分块)

www.cnblogs.com/shaokele/


bzoj3994: [SDOI2015]约数个数和##

  Time Limit: 20 Sec
  Memory Limit: 128 MB

Description###

  设d(x)为x的约数个数,给定N、M,求 $$\sum_{i=1}{n}\sum_{j=1}d(i j)$$
 

Input###

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

Output###

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

Sample Input###

  2
  
  7 4
  
  5 6
 

Sample Output###

  110
  
  121
  

题目地址:  bzoj3994: [SDOI2015]约数个数和

题目大意:   题目很简洁了:)####

  

题解:

  来自dalao的blog
  *p2

  \代码渲染好像出了点问题......


AC代码

#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int N=500005;
int n,m,Q,tot;
int u[N],f[N],g[N],pri[N];
bool fl[N];
inline void init(){
    u[1]=f[1]=1;
    for(int i=2;i<=N;i++){
        if(!fl[i]){
            pri[++tot]=i;
            g[i]=1;
            u[i]=-1;
            f[i]=2;
        }
        for(int j=1;j<=tot && i*pri[j]<=N;j++){
            fl[i*pri[j]]=1;
            if(i%pri[j]==0){
                g[i*pri[j]]=g[i]+1;
                u[i*pri[j]]=0;
                f[i*pri[j]]=f[i]/(g[i]+1)*(g[i]+2);
            }else{
                g[i*pri[j]]=1;
                u[i*pri[j]]=-u[i];
                f[i*pri[j]]=f[i]*2;
            }
        }
    }
    for(int i=2;i<=N;i++)
        f[i]+=f[i-1],u[i]+=u[i-1];
}
int main(){
    init();
    scanf("%d",&Q);
    while(Q--){
        scanf("%d%d",&n,&m);
        if(n>m)swap(n,m);
        ll ans=0;
        int l,r;
        for(l=1;l<=n;l=r+1){
            r=min(n/(n/l),m/(m/l));
            ans+=(ll)(u[r]-u[l-1])*f[n/l]*f[m/l];
        }
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2018-05-30 19:36  skl_win  阅读(132)  评论(0编辑  收藏  举报
Live2D