zoukankan      html  css  js  c++  java
  • 洛谷P3455 [POI2007]ZAP-Queries【莫比乌斯反演】

    传送门

    题解

    这算是莫比乌斯反演的最简模板了吧。
    首先手推公式,设:

    [f(d)=sum_{x=1}^{N}sum_{y=1}^{M}[gcd(x,y)=d]qquad (Nle M) ]

    根据 (F(n)=sum_{n|d}f(d)),得:

    [F(n)=igglfloorfrac{N}{n}igg floorigglfloorfrac{M}{n}igg floor ]

    根据莫比乌斯反演,得:

    [f(n)=sum_{n|d}mu(frac{d}{n})F(d)=sum_{n|d}mu(frac{d}{n})igglfloorfrac{N}{d}igg floorigglfloorfrac{M}{d}igg floor ]

    枚举 (t=frac{d}{n}),得:

    [f(n)=sum_{t=1}^{iglfloorfrac{N}{n}ig floor}mu(t)igglfloorfrac{N}{nt}igg floorigglfloorfrac{M}{nt}igg floor ]

    剩下的工作就要编程实现了,利用对 (mu) 求前缀和与整除分块,就可以在 (O(sqrt{n})) 以内回答每个问题了。
    感觉莫比乌斯反演最难的还是通过 (f(d)) 正确得到 (F(n))

    代码

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    using namespace std;
    typedef long long LL;
    const int N=5e4+10;
    int n,m,vis[N],prime[N],cnt,mu[N],sum[N],d;
    
    void init(int n){
    	mu[1]=1;
    	for(int i=2;i<=n;i++){
    		if(!vis[i]) {prime[++cnt]=i;mu[i]=-1;}
    		for(int j=1;j<=cnt&&1ll*i*prime[j]<=n;j++){
    			vis[i*prime[j]]=1;
    			if(i%prime[j]==0) {mu[i*prime[j]]=0;break;}
    			mu[i*prime[j]]=-mu[i];
    		}
    	}
    	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+mu[i];
    }
    
    int main(){
    	init(5e4);
    	int T;scanf("%d",&T);
    	while(T--){
    		LL ans=0;
    		scanf("%d%d%d",&n,&m,&d);
    		n/=d,m/=d;
    		for(int l=1,r;l<=min(n,m);l=r+1){
    			r=min(n/(n/l),m/(m/l));
    			if(r>min(n,m)) break;
    			ans+=1ll*(sum[r]-sum[l-1])*(n/l)*(m/l);
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    codna的安装与使用
    ubuntu 下修改MySQL 的root用户密码
    python中的排序
    CF 543C Remembering Strings
    CF 1119C Ramesses and Corner Inversion
    HihoCoder 1384 Genius ACM
    BZOJ3032 七夕祭
    Vjudge Code
    CF51C Three Base Stations
    Sumdiv POJ 1845
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12522868.html
Copyright © 2011-2022 走看看