zoukankan      html  css  js  c++  java
  • [POI2007]ZAP-Queries

    [POI2007] ZAP-Queries

    对于给定的整数 (a,b)(d) ,有多少正整数对 (x,y) ,满足 (x le a,y le b),并且 (gcd(x,y)=d)

    利用Mobius函数性质求解

    根据题意

    [ans=sum_{i=1}^a sum_{j=1}^b [{gcd(i,j)=d}] ]

    [ans=sum_{i=1}^{a/d} sum_{j=1}^{b/d}[gcd(i,j)=1] ]

    这里可以直接根据Mobius函数的性质,有

    [ans=sum_{i=1}^{a/d} sum_{j=1}^{b/d} sum_{p|gcd(i,j)}mu(p) ]

    换一个变量枚举,把最后一个求和提到前面,范围 (min(a/d,b/d)) ,那么

    [ans=sum_{p=1}^{min(a/d,b/d)}{ left({mu(p)} sum_{i=1}^{a/d} sum_{j=1}^{b/d} lfloorfrac{a}{p d} floor lfloorfrac{b}{p d} floor ight)} ]

    对上式稍作说明,令 (x=a/d,y=b/d)
    (p)(x,y) 的一个因子,在 (x) 的范围内有 (lfloorfrac{x}{p} floor)(p) 的倍数,对于 (y) 同理,所以每个因子 (p) 都有 (lfloorfrac{x}{p} floorlfloorfrac{y}{p} floor) 的贡献

    可以使用整除分块优化到 (O(sqrt n))

    利用Mobius反演求解

    首先,我们可以定义 (f(d))(F(d)) 如下:

    [f(d)=sum_{i=1}^Nsum_{j=1}^M[gcd(i,j)=d] ]

    [F(d)=sum_{i=1}^Nsum_{j=1}^M[d|gcd(i,j)] ]

    发现

    [sum_{n|d}f(d)=F(n)=lfloorfrac Nn floorlfloorfrac Mn floor ]

    莫比乌斯反演,得到:

    [f(n)=sum_{n|d}mu(lfloorfrac dn floor)F(d) ]

    于是

    [ans=f(d)=sum_{d|p}mu(lfloorfrac pd floor)F(p) ]

    换个元

    [ans=sum_{p'}mu(p')F( p' d ) =sum_{p'=1}^{min(lfloorfrac Nd floor,lfloorfrac Md floor)}mu(p')lfloorfrac N{p'd} floor lfloor frac M{p'd} floor ]

    (p') 写作 (p) ,得到

    [ans=sum_{p}mu(p)F( p d ) =sum_{p=1}^{min(lfloorfrac Nd floor,lfloorfrac Md floor)}mu(p)lfloorfrac N{pd} floor lfloor frac M{pd} floor ]

    后续求解方法与上一种相同。

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 50005;
    
    int pr[N],is[N],mu[N],cnt;
    
    signed main() {
    	mu[0]=mu[1]=1; is[1]=1;
    	for(int i=2;i<=N;i++) {
    		if(is[i]==0) {
    			pr[++cnt]=i;
    			mu[i]=-1;
    		}
    		for(int j=1; j<=cnt&&pr[j]*i<N; ++j) {
    			is[pr[j]*i]=1;
    			if(i%pr[j]==0) {
    				mu[pr[j]*i]=0;
    				break;
    			}
    			else {
    				mu[pr[j]*i]=-mu[i];
    			}
    		}
    	}
    	for(int i=1;i<=N;i++) mu[i]+=mu[i-1];
    	int T;
    	cin>>T;
    	while(T--) {
    		int n,m,d;
    		cin>>n>>m>>d;
    		n/=d; m/=d;
    		long long ans=0;
    		for(int l=1,r;l<=min(n,m);l=r+1) {
    			r=min(n/(n/l),m/(m/l));
    			ans+=(n/l)*(m/l)*(mu[r]-mu[l-1]);
    		}
    		cout<<ans<<endl;
    	}
    }
    
  • 相关阅读:
    ArcMap导出图层属性为excel表
    ArcMap面转为线
    vue(18)声明周期函数
    geoserver发布mbtiles文件
    docker部署geoserver
    vue(17)组件插槽slot的使用
    vue(16)父子组件之间直接相互访问
    MySQL常用查询语句积累
    数据库的基本设计
    HashMap学习
  • 原文地址:https://www.cnblogs.com/mollnn/p/11660842.html
Copyright © 2011-2022 走看看