zoukankan      html  css  js  c++  java
  • [bzoj3994] [SDOI2015]约数个数和

    Description

    设d(x)为x的约数个数,给定N、M,求 (sum_{i=1}^Nsum_{j=1}^Md(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

    solution

    前置知识:莫比乌斯反演

    首先对于(d)函数有一个结论:

    [d(ij)=sum_{d|i}sum_{d|j}[gcd(i,j)=1] ]

    我就是因为不知道这个结论推了半个小时无果QAQ

    证明大致如下:对于(ij)的每一个质因数(x),在(i)里出现了(a)次,在(j)里出现了(b)次,则总共有(a+b+1)中情况,

    然后进行转换,对于任意一个要选(q)个的情况:

    • (qleqslant a),就在(i)里选出(q)个,(j)里不选。
    • 否则就在(j)里选出(q-a)个,这里的在(j)里选实质上是在(i)里选满了,然后再在(j)里选的,为了不重复计数,在(j)里选(z)个实质上是选了(z+a)个。

    对于每一个质因数都这么考虑,然后只要保证(i,j)互质即为一种方案。

    然后把这个玩意带到题目给的式子里去,大力推一下,可得:

    [ans=sum_{d^prime=1}^{min(n,m)}mu(d^prime)sum_{d_1=1}^{lfloorfrac{n}{d^prime} floor}lfloorfrac{n}{d_1d^prime} floorsum_{d_2=1}^{lfloorfrac{m}{d^prime} floor}lfloorfrac{m}{d_2d^prime} floor ]

    (f)为式子后面那一块,即:

    [f(n)=sum_{i=1}^{n}lfloorfrac{n}{i} floor ]

    然后考虑下这个函数的性质:

    对于枚举的(i)(lfloorfrac{n}{i} floor)实质上就是(n)以内能整除(i)的数的个数。

    反过来想,对于每个数,它的每一个约数都对答案有1的贡献,所以(f(n))等价于(n)以内的所有数的约数个数和。

    然后线筛下约数个数和莫比乌斯函数,求下前缀和,整除分块下,就做完了。

    时间复杂度(O(n+qsqrt{n}))

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    
    void read(int &x) {
    	x=0;int f=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
    	if(x<0) putchar('-'),x=-x;
    	if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 5e4+1;
    
    int d[maxn],pri[maxn],tot,p[maxn],vis[maxn],mu[maxn];
    
    void sieve() {
    	d[1]=mu[1]=1;
    	for(int i=2;i<maxn;i++) {
    		if(!vis[i]) pri[++tot]=i,d[i]=2,p[i]=2,mu[i]=-1;
    		for(int t,j=1;j<=tot&&i*pri[j]<maxn;j++) {
    			vis[t=i*pri[j]]=1;
    			if(!(i%pri[j])) {
    				p[t]=p[i]+1;d[t]=d[i]/p[i]*p[t];
    				mu[t]=0;break;
    			}
    			p[t]=2,d[t]=d[i]*p[t];mu[t]=-mu[i];
    		}
    	}
    	for(int i=1;i<maxn;i++) mu[i]=mu[i]+mu[i-1];
    	for(int i=1;i<maxn;i++) d[i]=d[i-1]+d[i];
    }
    
    signed main() {
    	sieve();int t;read(t);
    	while(t--) {
    		int n,m;read(n),read(m);
    		int T=1,ans=0;if(n>m) swap(n,m);
    		while(T<=n) {
    			int pre=T;T=min(n/(n/T),m/(m/T));
    			ans+=(mu[T]-mu[pre-1])*d[n/T]*d[m/T];T++;
    		}write(ans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    最新金九银十JAVA面试总结:Java+并发+Spring+MySQL+分布式+Redis+算法+JVM等
    这是一份稳收秋招offer的jvm常见面试题指南,助你成为offer收割机
    五年java开发面经分享,注意这些细节让你offer拿到手软
    连尚网络Java实习面试(offer到手含面试经验及答案)
    汇通天下Java实习面试(offer到手含面试经验及答案)
    初速度Java实习面试(offer到手含面试经验及答案)
    斑马网络Java实习面试(offer到手含面试经验及答案)
    贝贝Java实习面试(offer到手含面试经验及答案)
    辣妈帮Java实习面试(offer到手含面试经验及答案)
    适赫物流Java实习面试(offer到手含面试经验及答案)
  • 原文地址:https://www.cnblogs.com/hbyer/p/10062542.html
Copyright © 2011-2022 走看看