莫比乌斯


YY的GCD

\[\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)\in prime] \]

\(\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;=\sum_{p\in prime}\sum_{i=1}^{\left\lfloor\dfrac{n}{p}\right\rfloor}\sum_{j=1}^{\left\lfloor\dfrac{m}{p}\right\rfloor}\sum_{d|gcd(i,j)}{\mu(d)}\)

\(\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;=\sum_{p\in prime}\sum_{d=1}^{min(n/p,m/p)}\mu(d)\:*\:{\left\lfloor\dfrac{n}{pd}\right\rfloor}\:*\:{\left\lfloor\dfrac{m}{pd}\right\rfloor}\)

\(\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;=\sum_{k=1}^{n}f(k)\:*\:{\left\lfloor\dfrac{n}{k}\right\rfloor}\:*\:{\left\lfloor\dfrac{m}{k}\right\rfloor}\)

\[f(x) = \sum_{p\in prime} \mu(\frac{x}{p}) \]

\[f(x) = \begin{cases}\mu(1)&x=1\\ \mu(i)&i \mod y= 0\\ -f(i) + \mu(i)& i \mod y \neq 0\end{cases} \]

数论分块 + 前缀和

#include
#define Starseven main
#define ll long long
namespace lyt {
	void read(int &x){
	char ch=getchar();int re=0,op=1;
	while(ch<'0'||ch>'9'){if(ch=='-') op=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){re=(re<<3)+(re<<1)+ch-'0';ch=getchar();}
	x = re * op;
	return ;
	}
	void read(long long &x){
	char ch=getchar();long long re=0,op=1;
	while(ch<'0'||ch>'9'){if(ch=='-') op=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){re=(re<<3ll)+(re<<1ll)+ch-'0';ch=getchar();}
	x = re * op;
	return ;
	}
	void write(int x){
		if(x<0){putchar('-');x=-x;}
		if(x>9) write(x/10);
		putchar(x%10+'0');
		return ;
	}//记得自己加空格和换行 
	void write(long long x){
		if(x<0){putchar('-');x=-x;}
		if(x>9) write(x/10);
		putchar(x%10+'0');
		return ;
	}//记得自己加空格和换行
	int max(int x,int y){return x m) n ^= m ^= n ^= m;
		ll ans = 0;
		for (int i = 1, j; i <= n; i = j + 1) {
			j = min(n / (n / i), m / (m / i));
			ans += 1ll * (f[j] - f[i - 1]) * (n / i) * (m / i);
		}
		write(ans);puts("");
	}
	return 0;	
}

约数个数和

闲话:

为什么大家做题是越做越熟练,我是越做越茫然?

\[\begin{aligned} \sum_{i=1}^{n}\sum_{j=1}^{m}d(ij) & = \sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{x|i}\sum_{y|j}[gcd(x,y)=1] \\ & = \sum_{x=1}^{n}\sum_{y=1}^{m}\:*\:{\left\lfloor\dfrac{n}{x}\right\rfloor}\:*\:{\left\lfloor\dfrac{m}{y}\right\rfloor}[gcd(x,y)=1] \\ & = \sum_{x=1}^{n}\sum_{y=1}^{m}{\left\lfloor\dfrac{n}{x}\right\rfloor}\:*\:{\left\lfloor\dfrac{m}{y}\right\rfloor}\:*\:\sum_{t|gcd(x,y)}\mu(t) \\ & = \sum_{t=1}^{min(n,m)}\mu(t)\times \sum_{x=1}^{\left\lfloor\dfrac{n}{t}\right\rfloor}\sum_{y=1}^{\left\lfloor\dfrac{m}{t}\right\rfloor}\left\lfloor\dfrac{n}{xt}\right\rfloor\:*\:\left\lfloor\dfrac{m}{xt}\right\rfloor \\ & = \sum_{t=1}^{min(n,m)}\mu(t)\times \sum_{x=1}^{\left\lfloor\dfrac{n}{t}\right\rfloor}\left\lfloor\dfrac{\left\lfloor\dfrac{n}{x}\right\rfloor}{t}\right\rfloor\times \sum_{x=1}^{\left\lfloor\dfrac{m}{t}\right\rfloor}\left\lfloor\dfrac{\left\lfloor\dfrac{m}{x}\right\rfloor}{t}\right\rfloor \end{aligned} \]

\[\text{莫比乌斯反演的“套路”} \text{设}f(x) = \sum_{i=1}^{x}{\left\lfloor\dfrac{x}{i}\right\rfloor} \]

\[ans=\sum_{t=1}^{min(n,m)}\mu(t)\times f(\left\lfloor\dfrac{n}{t}\right\rfloor)\times f(\left\lfloor\dfrac{m}{t}\right\rfloor) \]

\(\mu\)用前缀和

而f函数可以用数论分块\(O(\sqrt{N})\)

#include
#include
#include
#include
using namespace std;
 
const int maxn=50000+5;
 
int n,m,cas,cnt,mu[maxn],pri[maxn],vis[maxn];
long long ans,f[maxn];
 
inline long long calc(int x){
    long long res=0;
    for(int i=1,r;i<=x;i=r+1){
        r=x/(x/i);
        res+=(x/i)*(r-i+1);
    }
    return res;
}
 
inline void prework(void){
    mu[1]=1;
    for(int i=2;i<=50000;i++){
        if(!vis[i])
            vis[i]=1,pri[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&i*pri[j]<=50000;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0){
                mu[i*pri[j]]=0;break;
            }
            mu[i*pri[j]]=-mu[i];
        }
    }
    for(int i=1;i<=50000;i++) mu[i]+=mu[i-1],f[i]=calc(i);
}
 
signed main(void){
    scanf("%d",&cas);prework();
    while(cas--){
        scanf("%d%d",&n,&m);
        if(n>m) swap(n,m);ans=0;
        for(int i=1,r;i<=n;i=r+1){
            r=min(n/(n/i),m/(m/i));
            ans+=f[n/i]*f[m/i]*(mu[r]-mu[i-1]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

我裂开来

Crash的数字表格

\[ans=\sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j) \]

\[\begin{aligned} \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j) & = \sum_{t=1}^{min(n,m)}t\times \sum_{i=1}^{\left\lfloor\dfrac{n}{t}\right\rfloor}\sum_{j=1}^{\left\lfloor\dfrac{m}{t}\right\rfloor}(i\times j)[gcd(i,j=1)] \\ & = \sum_{t=1}^{min(n,m)}t\times \sum_{i=1}^{\left\lfloor\dfrac{n}{t}\right\rfloor}\sum_{j=1}^{\left\lfloor\dfrac{m}{t}\right\rfloor}i\times j\times(\sum_{h|gcd(i,j)}\mu(h)) \\ & = \sum_{t=1}^{min(n,m)}t\times\sum_{h=1}^{min(\left\lfloor\dfrac{m}{t}\right\rfloor,\left\lfloor\dfrac{n}{t}\right\rfloor)}\mu(h)\times h^2 \times\sum_{x=1}^{\left\lfloor\dfrac{n}{th}\right\rfloor}x \times \sum_{y=1}^{\left\lfloor\dfrac{m}{th}\right\rfloor}y \end{aligned} \]

然后我们观察式子

\[ans=\sum_{t=1}^{min(n,m)}t\times\sum_{h=1}^{min(\left\lfloor\dfrac{m}{t}\right\rfloor,\left\lfloor\dfrac{n}{t}\right\rfloor)}\mu(h)\times h^2 \times\sum_{x=1}^{\left\lfloor\dfrac{n}{th}\right\rfloor}x \times \sum_{y=1}^{\left\lfloor\dfrac{m}{th}\right\rfloor}y \]

我们就可以设

\[behind(x,y)=\sum_{h=1}^{min(x,y)}\mu(h)\times h^2 \times \sum_{i=1}^{\left\lfloor\dfrac{x}{h}\right\rfloor}i \times \sum_{j=1}^{\left\lfloor\dfrac{y}{h}\right\rfloor}j \]

这个式子是不是可以预处理一下?

就是三个前缀和拼凑!

然后数论分块可以求出\(behind(x,y)\)的值!

\[ans=\sum_{t=1}^{min(n,m)}t\times behind(\left\lfloor\dfrac{n}{t}\right\rfloor,\left\lfloor\dfrac{m}{t}\right\rfloor) \]

又是一个数论分块!

所以就解决了

#include
#define Starseven main
#define ll long long
namespace lyt {
	void read(int &x){
	char ch=getchar();int re=0,op=1;
	while(ch<'0'||ch>'9'){if(ch=='-') op=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){re=(re<<3)+(re<<1)+ch-'0';ch=getchar();}
	x = re * op;
	return ;
	}
	void read(long long &x){
	char ch=getchar();long long re=0,op=1;
	while(ch<'0'||ch>'9'){if(ch=='-') op=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){re=(re<<3ll)+(re<<1ll)+ch-'0';ch=getchar();}
	x = re * op;
	return ;
	}
	void write(int x){
		if(x<0){putchar('-');x=-x;}
		if(x>9) write(x/10);
		putchar(x%10+'0');
		return ;
	}//记得自己加空格和换行 
	void write(long long x){
		if(x<0){putchar('-');x=-x;}
		if(x>9) write(x/10);
		putchar(x%10+'0');
		return ;
	}//记得自己加空格和换行
	int max(int x,int y){return x mod) mu[i] %= mod;
		add[i] = add[i - 1] + i;
		if(add[i] > mod) add[i] %= mod;
	}
	return ;
}

ll Behind(ll x, ll y) {
	ll re = 0;
	for (ll h = 1; h <= min(x, y); h++) {
		ll g = min(x / (x / h), y / (y / h));
		ll a = x / h, b = y / h;
		re += (mu[g] - mu[h - 1]) % mod * add[a] % mod * add[b] % mod;
		if(re > mod) re %= mod;
		h = g;
	}
	re += mod;
	return (re % mod);
}

int Starseven(void) {
	ll n, m;
	read(n);
	read(m);
	if(n > m) swap(n, m);
	Init(); 
	ll ans = 0;
	for (ll t = 1; t <= n; t++) {
		ll x = min(n / (n / t), m / (m / t));
		ll behind = Behind(n / t, m / t);
		ans = (ans + (x - t + 1) * (x + t) / 2 * behind) % mod;
		t = x;
	}
	write(ans);puts("");
	return 0;	
}

数表

\[ans=\sum_{i=1}^{n}\sum_{j=1}^{m}[a\geq\sum_{d|gcd(i,j)}d]\times\sum_{d|gcd(i,j)}d \]

我们假设

\[G(n,m)=\sum_{d|gcd(n,m)}d \]

\[n \leq m \]

\[\begin{aligned} G(n,m) & = \sum_{d|gcd(n,m)}d \\ & = \sum_{d=1}^{n}d\times[d|gcd(n,m)] \\ & = \sum_{d=1}^nd\times[mn=\left\lfloor\dfrac{nm}{d^2}\right\rfloor\times d^2] \end{aligned} \]

这个思路有点难走,那我们换个思路

\[ans=(\sum_{i=1}^n\sum_{j=1}^m\sum_{d|gcd(i,j)}d)-(\sum_{i=1}^n\sum_{j=1}^m[a<\sum_{d|gcd(i,j)}d]\times\sum_{d|gcd(i,j)}d) \]

我们设前面的式子为sum(n,m),则

\[\begin{aligned} sum(n,m) & =\sum_{i=1}^n\sum_{j=1}^m\sum_{d|gcd(i,j)}d \\ & =\sum_{d=1}^nd\times \left\lfloor\dfrac{n}{d}\right\rfloor\times\left\lfloor\dfrac{m}{d}\right\rfloor \end{aligned} \]

这个可以用数论分块

然后我们发现其实后面的式子和上面没有用减法原理的式子一样,所以失败


这个时候,我们发现我们最开始枚举的东西就是除数函数!

其实我没有发现,是看题解才知道的

所以我们可以写出sum(n,m)的另一个版本

\[\begin{aligned} sum(n,m) & = \sum_{i=1}^n\sum_{j=1}^m\sigma(gcd(i,j)) \\ & = \sum_{t=1}^{n}\sigma(t)\sum_{i=1}^{\left\lfloor\dfrac{n}{t}\right\rfloor}\sum_{j=1}^{\left\lfloor\dfrac{m}{t}\right\rfloor}[gcd(i,j)=1] \\ & = \sum_{t=1}^{n}\sigma(t)\sum_{i=1}^{\left\lfloor\dfrac{n}{t}\right\rfloor}\sum_{j=1}^{\left\lfloor\dfrac{m}{t}\right\rfloor}\sum_{d|gcd(i,j)}\mu(d) \\ & = \sum_{t=1}^{n}\sigma(t)\sum_{d=1}^{\left\lfloor\dfrac{n}{t}\right\rfloor}\mu(d)\left\lfloor\dfrac{n}{dt}\right\rfloor\left\lfloor\dfrac{m}{dt}\right\rfloor \\ & =\sum_{T=1}^{n}\left\lfloor\dfrac{n}{T}\right\rfloor\left\lfloor\dfrac{m}{T}\right\rfloor\sum_{d|T}\sigma(d)\mu(\frac{T}{d}) \end{aligned} \]

此时,前面的求和可以分块\(O(n + m)\),后面的是个积性函数,可以预处理,然后就是O(1)

但是,不是每个东西都对答案有贡献,所以我们要排除掉没有贡献的.

然后就需要维护答案,想到维护这个词,在看一下式子,

\[\color{red}\text{单点修改,区间查询} \]

这不就是树状数组吗?

所以我鸽了……


P4450 双亲数

题解


P4449 于神之怒加强版

题解


P3911 最小公倍数之和

题解


P6156 简单题

题解


P1891 疯狂 LCM

题解