zoukankan      html  css  js  c++  java
  • BZOJ 3994: [SDOI2015]约数个数和 莫比乌斯反演

    Description

     设d(x)为x的约数个数,给定N、M,求  
     

    Input

    输入文件包含多组测试数据。

    第一行,一个整数T,表示测试数据的组数。
    接下来的T行,每行两个整数N、M。
     

    Output

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

     题解:

    有一个小结论:

    $d(ij)=sum_{i|n}sum_{j|n}[gcd(i,j)==1]$
     
    原式 $= sum_{i=1}^{n}sum_{j=1}^{m}d(ij)$
     
    $Rightarrowsum_{i=1}^{n}sum_{j=1}^{m}sum_{x|i}sum_{y|j}[gcd(x,y)==1]$
     
    $Rightarrowsum_{x=1}^{n}sum_{y=1}^{m}[gcd(x,y)==1]sum_{x|i}sum_{y|j}$
     
    $Rightarrowsum_{x=1}^{n}sum_{y=1}^{m}left lfloor  frac{n}{x} ight floorleft lfloor frac{m}{x} ight floor[gcd(x,y)==1]$
     
    $Rightarrowsum_{x=1}^{n}sum_{y=1}^{m}left lfloor  frac{n}{x} ight floorleft lfloor frac{m}{x} ight floorsum_{d|x,d|y}mu(d)$
     
    $Rightarrowsum_{d=1}^{n}mu(d)sum_{d|x}left lfloor frac{n}{x} ight floorsum_{d|y}left lfloor frac{m}{y} ight floor$  
     
    $Rightarrowsum_{d=1}^{n}mu(d)sum_{x=1}^{left lfloor frac{n}{d} ight floor}left lfloor frac{n}{xd} ight floorsum_{y=1}^{left lfloor frac{m}{d} ight floor}left lfloor frac{m}{yd} ight floor$
     
    剩下的交给整除分块计算就好了.
     
    最好提前预处理出来所有的前缀和. 
    #include<bits/stdc++.h>
    #define setIO(s) freopen(s".in","r",stdin)
    #define ll long long 
    #define maxn 100000 
    #define M 50002 
    using namespace std;
    int cnt; 
    bool vis[maxn]; 
    int prime[maxn], mu[maxn]; 
    ll sumv[maxn],Ge[maxn]; 
    ll Sum(int n)
    {
    	int i,j; 
    	ll re=0; 
    	for(i=1;i<=n;i=j+1)
    	{ 
    		j=n/(n/i);       
    		re+=(j-i+1)*(n/i); 
    	}
    	return re;   
    }
    void linear_shaker()
    {
    	int i,j; 
    	mu[1]=1; 
    	for(i=2;i<=M;++i) 
    	{
    		if(!vis[i]) prime[++cnt]=i, mu[i]=-1; 
    		for(j=1;j<=cnt&&1ll*i*prime[j]<=M;++j)
    		{
    			vis[i*prime[j]]=1; 
    			if(i%prime[j]==0) 
    			{
    				mu[i*prime[j]]=0; 
    				break; 
    			}
    			mu[i*prime[j]]=-mu[i]; 
    		}
    	}
    	for(i=1;i<=M;++i) sumv[i]=sumv[i-1]+mu[i];  
    	for(i=1;i<=M;++i) 
    	{
    		Ge[i]=Sum(i); 
    	}
    }
    int main()
    {
    // 	setIO("input"); 
    	linear_shaker();
    	int T,n,m,i,j; 
    	ll re; 
    	scanf("%d",&T); 
    	while(T--)
    	{
    		scanf("%d%d",&n,&m); 
    		if(n>m) swap(n,m); 
    		re=0; 
    		for(i=1;i<=n;i=j+1)
    		{
    			j=min(n/(n/i), m/(m/i)); 
    			re+=(sumv[j]-sumv[i-1])*Ge[n/i]*Ge[m/i]; 
    		}
    		printf("%lld
    ",re); 
    	} 
    	return 0; 
    }
      
    

      

  • 相关阅读:
    C++ 编码转换
    获取文件扩展名
    字符串分割(C++)(转载)
    Visual Leak Detector简明使用教程
    Win32 文件拖拽
    IMAP协议命令(详细)
    CreateDirectory 创建文件夹 CC++
    编程习惯总结
    GitHub上整理的一些工具,求补充
    jquery生成qrcode二维码
  • 原文地址:https://www.cnblogs.com/guangheli/p/11102507.html
Copyright © 2011-2022 走看看