• 牛客练习赛72D——brz的函数(莫比乌斯反演)


    令所求的式子为

    (f(n)=Sigma_iSigma_jmu(ij))

    则可以写出如下递推式,画个 (n*n) 的表格可辅助理解

    (f(n)=f(n-1)+2Sigma_{x=1}^nmu(xn))

    考虑 (Sigma_{x=1}^nmu(xn)) 的含义,这里先直接给出结果:

    (Sigma_{x=1}^nmu(xn)=Sigma_{x=1}^n[gcd(x,n)=1]*mu(x)*mu(n))

    上式的含义最简洁的一种理解方式是,由于莫比乌斯函数是积性的,因此当二者gcd为1时,有 (mu(xn)=mu(x)mu(n));而不为1的时候 (xn) 一定有平方因子,因此乘起来整个都是0。因此,可以写成上式。

    使用经典结论 ([dog=1]=Sigma_{d|dog}mu(d)) 可以继续得到:

    (Sigma_{x=1}^nmu(xn)=Sigma_{x=1}^n[gcd(x,n)=1]*mu(x)*mu(n))

    (=mu(n)Sigma_{x=1}^nmu(x)Sigma_{d|gcd(x,n)}mu(d))

    交换求和次序

    (=Sigma_{d|n}mu(d)*Sigma_{d|x,xleq n}mu(x))

    此时似乎很难往下化简了,我也一度陷入了懵逼当中,但当我冷静下来时,我发现化简到这一步已经够用了,因为上式直接计算似乎是(好吧我瞎猜的,应该差不多)个 (O(sqrt{n}*log(n))) 的复杂度,所以就直接计算就好了。

    这样,总的程序复杂度就是 (O(nsqrt{n}*log(n))) ,可以写了。

    具体实现的时候,要预处理出每个数的所有因数,并且要在发现某 (mu) 值为零时立刻continue剪个枝才能通过此题。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,n) for(int i=a;i<=n;i++)
    #define per(i,a,n) for(int i=n;i>=a;i--)
    #define pb push_back
    #define SZ(x) ((int)(x).size())
    #define fastin ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
    typedef long long ll;
    typedef pair<int,int> pii;
    typedef double db;
    
    const int N=2e5+5;
    int tot,flg[N+5],p[N+5],mu[N+5];
    void getMu() {
    	mu[1] = 1;
    	for (int i = 2; i <= N; ++i) {
    		if (!flg[i]) p[++tot] = i, mu[i] = -1;
    		for (int j = 1; j <= tot && i * p[j] <= N; ++j) {
    			flg[i * p[j]] = 1;
    			if (i % p[j] == 0) {
    				mu[i * p[j]] = 0;
    				break;
    			}
    			mu[i * p[j]] = -mu[i];
    		}
    	}
    }
    int ans[50010],t,n;
    vector<int> fac[50010];
    int main(){
    	getMu();
    	ans[1]=1;
    	rep(i,1,50000){
    		for(int j=i;j<=50000;j+=i){
    			fac[j].pb(i);
    		}
    	}
    	rep(i,2,50000){
    		if(!mu[i]){
    			ans[i]=ans[i-1];continue;
    		}
    		int cof=2*mu[i];
    		int sum=0;
    		for(auto d:fac[i]){
    			if(!mu[d])	continue;
    			int tmp=0;
    			for(int x=d;x<i;x+=d){
    				tmp+=mu[x];
    			}
    			tmp*=mu[d];
    			sum+=tmp;
    		}
    		ans[i]=ans[i-1]+cof*sum;
    	}
    	cin>>t;
    	while(t--){
    		cin>>n;
    		printf("%d
    ",ans[n]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [na][dhcp]华为DHCP-重要
    [na]win PPTP场景与搭建
    [na]锐起无盘机并发部署多台windows
    [na]wireshark抓包排错-tcp.flags.reset
    [svc]mousedos网络批量部署xp
    [na]诺顿ghost磁盘对刻(备份系统分区或数据分区)
    [na]代理arp导致的问题(路由卷)
    [na]pc加入域认证细节
    【VS开发】【智能语音处理】VS中声音的采集实现
    【VS开发】【智能语音处理】MATLAB 与 音频处理 相关内容摘记
  • 原文地址:https://www.cnblogs.com/fried-chicken/p/13939460.html
Copyright © 2020-2023  润新知