zoukankan      html  css  js  c++  java
  • 【XSY3804】QQ数(莫比乌斯函数,容斥)

    题面

    在这里插入图片描述

    题解

    明显地,这个QQ数可以用 μ mu μ 表示,于是询问就变成了这样:

    ∑ i = 1 n ∑ d ∣ i ( 1 − μ ( d ) 2 ) = ∑ d = 1 n ⌊ n d ⌋ ( 1 − μ ( d ) 2 ) egin{aligned} & sum_{i=1}^nsum_{d|i}left(1-mu(d)^2 ight)\ =& sum_{d=1}^nleftlfloorfrac{n}{d} ight floorleft(1-mu(d)^2 ight) end{aligned} =i=1ndi(1μ(d)2)d=1ndn(1μ(d)2)
    发现 ⌊ n d ⌋ lfloordfrac{n}{d} floor dn 是可以整除分块的,但是 n ≤ 1 0 9 nleq 10^9 n109 无法线性筛 μ mu μ

    考虑如何更快地求出 ∑ i = 1 n ( 1 − μ ( d ) 2 ) sumlimits_{i=1}^nleft(1-mu(d)^2 ight) i=1n(1μ(d)2),也就是 1 ∼ n 1sim n 1n 中的QQ数个数。

    但是有这么一个神奇的式子:
    ∑ i = 1 n ( 1 − μ ( i ) 2 ) = ∑ x = 2 n − μ ( x ) ⌊ N x 2 ⌋ sum_{i=1}^nleft(1-mu(i)^2 ight)=sum_{x=2}^{sqrt n}-mu(x)lfloorfrac{N}{x^2} floor i=1n(1μ(i)2)=x=2n μ(x)x2N
    证明:

    首先,对于每一个QQ数 a a a,他肯定可以拆分成这种形式: a = x 2 y a=x^2 y a=x2y(其中 x x x 不是QQ数),也就是说,我们把每一个QQ数表示成一个非QQ数的平方再乘上一个数。

    比如QQ数 2 4 × 3 3 × 5 2^4 imes 3^3 imes 5 24×33×5 可以拆分为 ( 2 × 3 ) 2 × … (2 imes 3)^2 imes dots (2×3)2× x = 2 × 3 x=2 imes 3 x=2×3)或者 2 2 × … 2^2 imes dots 22× x = 2 x=2 x=2)或者 3 2 × … 3^2 imes dots 32× x = 3 x=3 x=3)。

    那么 ∑ x = 2 n − μ ( x ) ⌊ N x 2 ⌋ sumlimits_{x=2}^{sqrt n}-mu(x)lfloordfrac{N}{x^2} floor x=2n μ(x)x2N 就可以看成是枚举每一个 x x x,然后再枚举有多少个 a a a,然后再配上一个 − μ ( x ) -mu(x) μ(x) 去重。(至于能去重的原因结合 μ mu μ 的定义以及这个式子想一想: ∑ i = 1 n ( − 1 ) i ( n i ) = − 1 sumlimits_{i=1}^n(-1)^idbinom{n}{i}=-1 i=1n(1)i(in)=1

    那么就能在 n sqrt n n 的时间内求出 ∑ i = 1 n ( 1 − μ ( d ) 2 ) sumlimits_{i=1}^nleft(1-mu(d)^2 ight) i=1n(1μ(d)2) 了。

    时间复杂度比较玄学,反正能过。

    代码如下:

    #include<bits/stdc++.h>
    
    #define SN 32000
    #define ll long long
    
    using namespace std;
    
    int ql,qr;
    int cnt,prime[SN],mu[SN];
    bool notprime[SN];
    
    void init()
    {
    	mu[1]=1;
    	for(int i=2;i<=31622;i++)
    	{
    		if(!notprime[i])
    		{
    			prime[++cnt]=i;
    			mu[i]=-1;
    		}
    		for(int j=1;j<=cnt&&i*prime[j]<=31622;j++)
    		{
    			notprime[i*prime[j]]=1;
    			if(!(i%prime[j])) break;
    			mu[i*prime[j]]=-mu[i];
    		}
    	}
    }
    
    int summu(int n)
    {
    	ll ans=0;
    	for(int i=2;i*i<=n;i++)
    		ans-=mu[i]*(n/i/i);
    	return ans;
    }
    
    ll solve(int n)
    {
    	ll ans=0;
    	for(int l=1,r,last=0;l<=n;l=r+1)
    	{
    		r=n/(n/l);
    		ll tmp=summu(r);
    		ans+=(n/l)*(tmp-last);
    		last=tmp;
    	}
    	return ans;
    }
    
    int main()
    {
    	init();
    	scanf("%d%d",&ql,&qr);
    	printf("%lld
    ",solve(qr)-solve(ql-1));
    	return 0;
    }
    
  • 相关阅读:
    git基本报错处理
    上传本地文件到gitee
    Pycharm Process finished with exit code -1073741819 (0xC0000005)
    linux ubuntu 安装后的配置
    Anaconda 和 jupyter notebook入门
    LaTeX公式小结--持续更新中
    markdown基本语法
    Python数据类型的整理
    linux磁盘分区与挂载
    第一章linux系统概述
  • 原文地址:https://www.cnblogs.com/ez-lcw/p/14448636.html
Copyright © 2011-2022 走看看