1. 程式人生 > 其它 >[省選集訓2022] 模擬賽15

[省選集訓2022] 模擬賽15

Lost

題目描述

定義布林函式 \(f(x)\) 表示 \(x\) 是否為完全平方數,給定 \(n,m\),求:

\[\sum_{i=1}^n\sum_{j=1}^m f(ij) \]

\(n,m\leq 10^{12}\)

解法

我們向深入考察 \(f(ij)\) 的性質,考慮 \(ij\) 為完全平方數的充要條件是,存在唯一的 \(d\) 滿足 \(i=dx^2,j=dy^2\),考慮 \(d\) 是一個只包含一次質因子的數,所以可以列舉 \(d\)

\[\sum_{d=1}^{n}\sqrt{\frac{n}{d}}\cdot\sqrt{\frac{m}{d}}\cdot \mu(d)^2 \]

考慮對 \(u(d)^2\)

進行變換,有等式 \(\sum_{i^2|d}\mu(i)=\mu(d)^2\),證明可以考慮如果 \(d\) 是完全平方數,那麼 \(i\) 可以自由選擇包不包含某個質數 \(p\),包含和不包含的 \(\mu\) 之和是相反數,所以抵消。而否則 \(i\) 只能取 \(1\),就和 \(\mu(d)^2\) 相等了。我們帶入這個等式:

\[\sum_{d=1}^{n}\sqrt{\frac{n}{d}}\cdot\sqrt{\frac{m}{d}}\cdot \sum_{i^2|d}\mu(i) \]

按照套路可以列舉 \(i\) 來化簡這個式子:

\[\sum_{i=1}^{\sqrt n}\mu(i)\sum_{d}\sqrt{\frac{n/i^2}{d}}\cdot\sqrt {\frac{m/i^2}{d}} \]

注意根號的時候要強轉 \(\tt ll\)

再做乘法才是符合組合意義的,外層可以直接列舉,內層整除分塊,注意我們只對 \(\mu(i)\) 有值的位做整除分塊,那麼跑得就會非常快,其實是我算不來複雜度

補充:直接對 \(d\) 不包含平方因子這個條件做莫比烏斯反演,也可以得到最後的式子。

#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
const int M = 1000005;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,cnt,ans,vis[M],p[M],mu[M];
void init(int n)
{
	mu[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!vis[i]) p[++cnt]=i,mu[i]=-1;
		for(int j=1;j<=cnt && i*p[j]<=n;j++)
		{
			vis[i*p[j]]=1;
			if(i%p[j]==0) break;
			mu[i*p[j]]=-mu[i];
		}
	}
}
int work(int n,int m)
{
	int res=0;
	for(int l=1,r=1;l<=n;l=r+1)
	{
		r=min(n/(n/l),m/(m/l));
		res+=(r-l+1)*(int)sqrt(n/l)*(int)sqrt(m/l);
	}
	return res;
}
signed main()
{
	freopen("lost.in","r",stdin);
	freopen("lost.out","w",stdout);
	n=read();m=read();init(1e6);
	if(n>m) swap(n,m);
	for(int i=1,t=sqrt(n);i<=t;i++) if(mu[i])
		ans+=mu[i]*work(n/i/i,m/i/i);
	printf("%lld\n",ans);
}