返回顶部

莫比乌斯反演

数论分块

常与数列分块连用
向下取整括号一定要加对

		int End=0,N=a/d,M=b/d;
		if(N<M) swap(N,M);
		for(int Start=1;Start<=M;Start=End+1)
		{
			End=min(N/(N/Start),M/(M/Start));//注意边界
			ans+=(sum[End]-sum[Start-1])*(long long)(N/Start)*(M/Start);//注意括号
		}	

常见公式

\[\sum_{d|n}\mu(d)=[n=1] \]

\[\sum_{d|n}\phi (d)=n \]

\[若f(n)=\sum_{d|n}g(d),则有g(n)=\sum_{d|n}\mu(d)f(\frac{n}{d}) \]

筛法求约数个数

OIWIKI
\(f_i\)表示\(i\)的约数个数,\(g_i\)表示\(i\)的最小质因子的\(p^0+p^1+p^2+...+p^k\)

点击查看代码
vector<int> pri;
bool not_prime[N];
int g[N], f[N];

void pre(int n) {
  g[1] = f[1] = 1;
  for (int i = 2; i <= n; ++i) {
    if (!not_prime[i]) {
      pri.push_back(i);
      g[i] = i + 1;
      f[i] = i + 1;
    }
    for (int pri_j : pri) {
      if (i * pri_j > n) break;
      not_prime[i * pri_j] = true;
      if (i % pri_j == 0) {
        g[i * pri_j] = g[i] * pri_j + 1;
        f[i * pri_j] = f[i] / g[i] * g[i * pri_j];
        break;
      }
      f[i * pri_j] = f[i] * f[pri_j];
      g[i * pri_j] = 1 + pri_j;
    }
  }
}

例题

P3455 [POI2007] ZAP-Queries

最基础的一题
假设\(a<=b\)

\[\large \sum_{i=1}^a\sum_{j=1}^b[gcd(i,j)=d] \]

\[\large \sum_{i=1}^{\lfloor {\frac{a}{d}} \rfloor}\sum_{j=1}^{\lfloor {\frac{b}{d}} \rfloor}[gcd(i,j)=1] \]

\[\large \sum_{i=1}^{\lfloor {\frac{a}{d}} \rfloor}\sum_{j=1}^{\lfloor {\frac{b}{d}} \rfloor}\sum_{t|gcd(i,j)}\mu(t) \]

\[\large \sum_{t=1}^n\mu(t)\lfloor {\frac{a}{dt}} \rfloor \lfloor {\frac{b}{dt}} \rfloor \]

单次询问\(O(\sqrt n)\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
//#define int long long
#define pb push_back
// #pragma comment(linker, “/STACK:512000000,512000000”) 
using namespace std;
const int N = 1e6+5;
ll mu[N],n,tot,pr[N],m,sum[N];bool is[N];
ll a,b,d;
void getMu(int n)
{
	mu[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!is[i])
		{
			pr[++tot]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=tot&&i*pr[j]<=n;j++)
		{
			is[i*pr[j]]=1;
			if(i%pr[j]==0)
			{
				mu[i*pr[j]]=0;
				break;
			}
			mu[i*pr[j]]=-mu[i];
		}
	}
	for(int i=1;i<=n;i++)
	{
		// cout<<mu[i]<<" ";
		sum[i]=sum[i-1]+mu[i];
	}
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	int T;
	cin>>T;
	getMu(5e4);
	while(T--)
	{
		cin>>a>>b>>d;
		ll ans=0;
		if(a>b)swap(a,b);
		// int End=0,N=a/d,M=b/d;
		// if(N<M) swap(N,M);
		// for(int Start=1;Start<=M;Start=End+1)
		// {
		// 	End=min(N/(N/Start),M/(M/Start));
		// 	ans+=(sum[End]-sum[Start-1])*(long long)(N/Start)*(M/Start);
		// }		
		int l=1,r;a/=d;b/=d;
		while(l<=a)
		{
			r=min(a/(a/l),b/(b/l));
			ans+=1ll*(sum[r]-sum[l-1])*(long long)(a/l)*(b/l);
			l=r+1;
		}
		cout<<ans<<endl;
	}
	return 0;
}

P2522 [HAOI2011] Problem b

与上一题相似,只需要容斥一下即可,具体为\(ans((1,b),(1,d))-ans((1,a-1),(1,d))-ans((1,b),(1,c-1))+ans((a-1),(c-1))\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
//#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int N =5e4+5;
int a,b,c,d,k,mu[N],tot,pr[N],sum[N];bool is[N];
void getMu(int n)
{
	mu[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!is[i])
		{
			pr[++tot]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=tot&&pr[j]*i<=n;j++)
		{
			is[pr[j]*i]=1;
			if(i%pr[j]==0)break;
			mu[i*pr[j]]=-mu[i];
		}
	}
	for(int i=1;i<=n;i++)
	{
		sum[i]=sum[i-1]+mu[i];
		// cout<<mu[i]<<" ";
	}
}
ll solve(ll n,ll m,ll k)
{
	n/=k;m/=k;
	if(n>m)swap(n,m);
	int l=1,r;
	ll res=0;
	while(l<=n)
	{
		r=min(n/(n/l),m/(m/l));
		res+=(sum[r]-sum[l-1])*(n/l)*(m/l);
		l=r+1;
	}
	// cout<<res<<endl;
	return res;
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	int T;
	cin>>T;
	// cout<<"*****"<<endl;
	getMu(5e4);
	// cout<<"*****"<<endl;
	while(T--)
	{
		cin>>a>>b>>c>>d>>k;
		cout<<solve(b,d,k)-solve(a-1,d,k)-solve(b,c-1,k)+solve(a-1,c-1,k)<<endl;
	}
	return 0;
}

P2257 YY的GCD

同理

\[\large \sum_{k=1}^n\sum_{t=1}^{\lfloor { \frac{n}{k}}\rfloor}\mu(t)\lfloor {\frac{n}{kt}} \rfloor \lfloor {\frac{m}{kt}} \rfloor (k\in prime) \]

这样还没完,会超时,我们设\(T=kt\),则

\[\large \sum_{T=1}^n\lfloor {\frac{n}{T}} \rfloor\lfloor {\frac{m}{T}} \rfloor \times \sum_{k|T}\mu(\frac{T}{k}) (k\in prime) \]

我们发现这东西是可以预处理出来的(类似狄利克雷前缀和)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
//#define int long long
#define pb push_back
// #pragma comment(linker, “/STACK:512000000,512000000”) 
using namespace std;
const int N = 1e7+5;
int mu[N],n,tot,pr[N],m,f[N],sum[N];bool is[N];
void getMu(int n)
{
	mu[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!is[i])
		{
			pr[++tot]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=tot&&i*pr[j]<=n;j++)
		{
			is[i*pr[j]]=1;
			if(i%pr[j]==0)
			{
				mu[i*pr[j]]=0;
				break;
			}
			mu[i*pr[j]]=-mu[i];
		}
	}
	for(int i=1;i<=tot;i++)
	{
		for(int j=1;pr[i]*j<=n;j++)
		{
			f[pr[i]*j]+=mu[j];
		}
	}
	for(int i=1;i<=n;i++)
	{
		sum[i]=sum[i-1]+f[i];
	}
}

int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	int T;
	cin>>T;
	getMu(1e7);
	// for(int i=1;i<=10;i++)cout<<mu[i]<<" ";
	// cout<<endl;
	while(T--)
	{
		cin>>n>>m;
		if(n>m)swap(n,m);
		ll ans=0;
		int l=1,r;
		while(l<=n)
		{
			r=min(n/(n/l),m/(m/l));
			ans+=1ll*(sum[r]-sum[l-1])*(long long)(n/l)*(m/l);
			l=r+1;
		}
		cout<<ans<<endl;
	}
	return 0;
}

P3327 [SDOI2015] 约数个数和

首先知道一个性质:
$$\large d(ij)=\sum_{x|i}\sum_{y|j}[gcd(x,y)=1]$$
$$\large ans=\sum_{i=1}^n \sum_{j=1}^m \sum_{x|i}\sum_{y|j}[gcd(x,y)=1]$$
$$\large ans=\sum_{x=1}^n \sum_{y=1}^m \sum_{i=1}^{n} \sum_{j=1}^{m} [x|i][y|i][gcd(x,y)=1]$$
$$\large ans=\sum_{x=1}^n \sum_{y=1}^m \lfloor {\frac{n}{x}} \rfloor \lfloor {\frac{m}{y}} \rfloor [gcd(x,y)=1]$$
$$\large ans=\sum_{x=1}^n \sum_{y=1}^m \lfloor {\frac{n}{x}} \rfloor \lfloor {\frac{m}{y}} \rfloor \sum_{t|gcd(x,y)}\mu(t)$$ $$\large ans=\sum_{t=1}^n\mu(t) \sum_{x=1}^{\lfloor {\frac{n}{t}} \rfloor} \sum_{y=1}^{\lfloor {\frac{m}{t}} \rfloor} \lfloor {\frac{n}{xt}} \rfloor \lfloor {\frac{m}{yt}} \rfloor$$
后面两项我们可以预处理出来,用数论分块,\(O(n^2)->O(n\sqrt n)\)
查询\(O(T\sqrt n)\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
//#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int N =5e4+5;
ll n,m,mu[N],tot,pr[N],sum[N],fx[N];bool is[N];
void getMu(int n)
{
	mu[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!is[i])
		{
			pr[++tot]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=tot&&pr[j]*i<=n;j++)
		{
			is[pr[j]*i]=1;
			if(i%pr[j]==0)break;
			mu[i*pr[j]]=-mu[i];
		}
	}
	for(int i=1;i<=n;i++)
	{
		sum[i]=sum[i-1]+mu[i];
		// cout<<mu[i]<<" ";
	}
	for(int i=1;i<=n;i++)
	{
		ll l=1,r;
		ll res=0;
		while(l<=i)
		{
			r=i/(i/l);
			res+=1ll*(r-l+1ll)*(i/l);
			l=r+1;
		}
		fx[i]=res;
	}
}
ll solve(ll n,ll m)
{
	if(n>m)swap(n,m);
	int l=1,r;
	ll res=0;
	while(l<=n)
	{
		r=min(n/(n/l),m/(m/l));
		res+=(sum[r]-sum[l-1])*fx[n/l]*fx[m/l];
		l=r+1;
	}
	// cout<<res<<endl;
	return res;
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	int T;
	cin>>T;
	// cout<<"*****"<<endl;
	getMu(5e4);
	// cout<<"*****"<<endl;
	while(T--)
	{
		cin>>n>>m;
		cout<<solve(n,m)<<endl;
	}
	return 0;
}

P3312 [SDOI2014] 数表

前置知识:\(\sigma\)除数函数

\[\sigma_k(n)=\sum_{d|n}d^k(d\in N) \]

特殊的:
\(\sigma_1(n)即为n的因数和\)
\(\sigma_0(n)即为n的因数个数\)

本题即为

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

\[\sum_{d=1}^n\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor}\sigma_1(d)[gcd(i,j)=1] \]

\[\sum_{d=1}^n\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor}\sigma_1(d)\sum_{t|gcd(i,j)}\mu(t) \]

\[\sum_{d=1}^n\sigma_1(d)\sum_{t=1}^{\lfloor{\frac{n}{x}}\rfloor}\mu(t)\lfloor{\frac{n}{dt}}\rfloor\lfloor{\frac{m}{dt}}\rfloor \]

\(T=dt\),则

\[\sum_{T=1}^n\lfloor{\frac{n}{T}}\rfloor\lfloor{\frac{m}{T}}\rfloor\sum_{t|T}\sigma_1{(\frac{T}{t})}\mu(t) \]

如何预处理\(\sigma_1\),暴力就好了,\(O(\sum_{i=1}^n\frac{n}{i}=nl_nn)\)
\(a\)排序,树状数组插入维护\(\sum_{t|T}\sigma_1{(\frac{T}{t})}\mu(t)\)即可

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int N =1e5+5,mod=(1LL<<31);
ll n,m,mu[N],tot,pr[N],sum[N],g[N];bool is[N];
struct Node
{
	int id,z;
}d[N];
void getMu(int n)
{
	mu[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!is[i])
		{
			pr[++tot]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=tot&&pr[j]*i<=n;j++)
		{
			is[pr[j]*i]=1;
			if(i%pr[j]==0)
			{
				break;
			}
			mu[i*pr[j]]=-mu[i];
		}
	}
	for(int i=1;i<=n;i++)
	{
		sum[i]=sum[i-1]+mu[i];
		// cout<<mu[i]<<" ";
	}
	for(int i=1;i<=n;i++)
		for(int j=i;j<=n;j+=i)
			g[j]+=i;
	for(int i=1;i<=n;i++)
	{
		d[i].id=i;d[i].z=g[i];
		// cout<<d[i].id<<" "<<d[i].z<<endl;
	}
	sort(d+1,d+1+n,[&](Node a,Node b)
	{
		return a.z<b.z;
	});
}
struct Query
{
	int n,m,a,id;
	bool operator < (const Query& A)const
	{
		return a<A.a;
	}
}q[N];
struct BIT
{
	ll c[N];
	int lowbit(int x){return x&-x;}
	void update(int x,int val){while(x<=1e5)c[x]+=val,c[x]%=mod,x+=lowbit(x);}
	int query(int x){ll res=0;while(x)res+=c[x]%mod,x-=lowbit(x);return res;}
}bit;
void add(int t)
{
	for(int i=1;i*t<=1e5;i++)bit.update(i*t,mu[i]*g[t]);
}
ll solve(ll n,ll m)
{
	if(n>m)swap(n,m);
	int l=1,r;
	ll res=0;
	while(l<=n)
	{
		r=min(n/(n/l),m/(m/l));
		res+=(bit.query(r)-bit.query(l-1))*(n/l)*(m/l);
		res%=mod;
		// cout<<res<<endl;
		l=r+1;
	}
	// cout<<res<<endl;
	return (res+mod)%mod;
}
int Ans[N];
signed main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	int T;n=1e5;
	cin>>T;
	// cout<<T<<endl;
	getMu(1e5);
	// cout<<"*****"<<endl;
	for(int i=1;i<=T;i++)
	{
		cin>>q[i].n>>q[i].m>>q[i].a;
		q[i].id=i;
		// cout<<solve(n,m)<<endl;
	}
	sort(q+1,q+1+T);
	int now=0;
	for(int i=1;i<=T;i++)
	{
		while(d[now+1].z<=q[i].a&&now<=1e5)now++,add(d[now].id);
		Ans[q[i].id]=solve(q[i].n,q[i].m);
	}
	for(int i=1;i<=T;i++)
	{
		cout<<Ans[i]<<endl;
	}
	return 0;
}

P3704 [SDOI2017] 数字表格

\[\prod_{i=1}^n\prod_{j=1}^mf(gcd(i,j)) \]

\[\prod_{d=1}^n\prod_{i=1}^n\prod_{j=1}^mf(d)[gcd(i,j)=1] \]

\[\prod_{d=1}^nf(d)^{\sum_{i=1}^{\lfloor {\frac{n}{d}}\rfloor}\sum_{j=1}^{\lfloor {\frac{m}{d}}\rfloor}[gcd(i,j)=1]} \]

\[\prod_{d=1}^nf(d)^{\sum_{t=1}^{\lfloor {\frac{n}{d}}\rfloor}\mu(t){\lfloor {\frac{n}{td}}\rfloor}{\lfloor {\frac{m}{td}}\rfloor}} \]

\(T=dt\)

\[\prod_{T=1}^n(\prod_{d|T}f(d)^{\sum_{t=1}^{\lfloor {\frac{n}{d}}\rfloor}\mu(\frac{T}{d})) })^{{\lfloor {\frac{n}{T}}\rfloor}{\lfloor {\frac{m}{T}}\rfloor}}\]

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
//#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int N = 1e6+5,mod=1e9+7;
ll mu[N],pr[N],tot,sum[N];bool is[N];
ll f[N],n,m,g[N],ans[N],F[N];
ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=ans*a%mod;
		b>>=1;a=a*a%mod;
	}
	return ans;
}
void getMu(int n)
{
	mu[1]=1;f[1]=f[2]=1;F[1]=F[0]=1;g[1]=1;
	for(int i=2;i<=n;i++)
	{
		f[i]=(f[i-1]+f[i-2])%mod;
		g[i]=qpow(f[i],mod-2);
		F[i]=1;
		if(!is[i])
		{
			pr[++tot]=i;mu[i]=-1;
		}
		for(int j=1;j<=tot&&pr[j]*i<=n;j++)
		{
			is[pr[j]*i]=1;
			if(i%pr[j]==0)break;
			mu[pr[j]*i]=-mu[i];
		}
	}
	// for(int i=1;i<=n;i++)sum[i]=sum[i-1]+mu[i];

}
ll solve(ll n,ll m)
{
	ll l=1,r=0;
	if(n>m)swap(n,m);
	ll res=1;
	while(l<=n)
	{
		r=min(n/(n/l),m/(m/l));
		res=res*qpow(F[r]*qpow(F[l-1],mod-2)%mod,(n/l)*(m/l)%(mod-1))%mod;
		l=r+1;
	}
	return res;
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	getMu(1e6);
	int T;
	cin>>T;
	for(int i=1;i<=1e6;i++)
	{
		if(!mu[i])continue;
		for(int j=i;j<=1e6;j+=i)
			F[j]=(F[j]*(mu[i]==1?f[j/i]:g[j/i]))%mod;

	}
	for(int i=2;i<=1e6;i++)
	{
		F[i]=F[i-1]*F[i]%mod;
		// cout<<F[i]<<endl;
	}
	// for(int i=1;i<=1e6;i++)ans[i]=ans[i-1]*g[i]%mod;
	while(T--)
	{
		cin>>n>>m;
		cout<<(solve(n,m)+mod)%mod<<endl;
	}
	return 0;
}

P4449 于神之怒加强版

\[\sum_{d=1}^n\sum_{i=1}^n\sum_{j=1}^md^k[gcd(i,j)=d] \]

\[\sum_{d=1}^n{\lfloor {\frac{n}{d}}\rfloor}{\lfloor {\frac{m}{d}}\rfloor}d^k\sum_{t|gcd(i,j)}\mu(t) \]

\[ans=\sum_{d=1}^{min(n,m)} \lfloor \frac n d \rfloor * \lfloor \frac m d \rfloor*\sum_{i|d} \mu(\frac d i)* i^{k} \]

你尝试把他变成 \(\varphi\),但你发现答案成了这样:

\[ans=\sum_{d=1}^{min(n,m)} \lfloor \frac n d \rfloor * \lfloor \frac m d \rfloor* \varphi(d)\sum_{i|d} i^{k-1} \]

但是没用

\[g(x)=x^k \]

\[G(n)=\sum_{i|n}g(i)* \mu(\frac n i) \]

那么答案就成了:

\[ans=\sum_{d=1}^{min(n,m)}G(d)* \lfloor \frac n d \rfloor * \lfloor \frac m d \rfloor \]

先说结论:

\[ G(a* b)=G(a)* G(b)(\gcd(a,b)=1) \]

\[G(a* b)=G(a)* b^k(\gcd(a,b) \ne 1\land b\in\mathbb P) \]

如何证明:因为线性筛,就设\(b\)为质数显然若\(gcd(a,b)=1,那么G(ab)=G(a)\times G(b)\)

\[G(p)=g(p)\mu(1)+g(1)\mu(p)=p^k-1,p\in prime \]

\[G(p^{x+1})=g(p^x)\mu(p)+g(p^{x+1})\mu(1),因为其他值有平方因子\mu全为0 \]

\[G(p^{x+1})=p^{(x+1)k}-p^{xk} \]

\(gcd(a,b)\ne 1\),且\(b\)为质数,则\(a\)中含有\(b\)这个质因子,唯一分解定理知道\(a=\prod p_i^{c_i}\)
那么等价于\(G(b^{c+1})=G(b^c)\times x(x未知)\)
有刚才结论\(G(p^{x+1})=p^{(x+1)k}-p^{xk}\),所以两边一消,\(x=b^k\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
//#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int N = 5e6+5,mod=1e9+7;
ll mu[N],pr[N],tot,sum[N];bool is[N];
ll n,m,g[N],k;
ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=ans*a%mod;
		b>>=1;a=a*a%mod;
	}
	return ans;
}
void getMu(int n)
{
	mu[1]=1;g[1]=1;
	for(int i=2;i<=n;i++)
	{

		if(!is[i])
		{
			pr[++tot]=i;mu[i]=-1;
			g[i]=(qpow(i,k)-1+mod)%mod;
		}
		for(int j=1;j<=tot&&pr[j]*i<=n;j++)
		{
			is[pr[j]*i]=1;
			if(i%pr[j]==0)
			{
				g[pr[j]*i]=g[i]*(g[pr[j]]+1)%mod;
				break;
			}
			mu[pr[j]*i]=-mu[i];
			g[pr[j]*i]=g[pr[j]]*g[i]%mod;
		}
	}
	for(int i=1;i<=n;i++)sum[i]=(sum[i-1]+g[i])%mod;

}
ll solve(ll n,ll m)
{
	ll l=1,r=0;
	if(n>m)swap(n,m);
	ll res=0;
	while(l<=n)
	{
		r=min(n/(n/l),m/(m/l));	
		res=(res+(sum[r]-sum[l-1]+mod)%mod*(n/l)%mod*(m/l)%mod)%mod;
		l=r+1;
	}
	return res;
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	
	int T;
	cin>>T>>k;
	getMu(5e6);
	while(T--)
	{
		cin>>n>>m;
		cout<<(solve(n,m)+mod)%mod<<endl;
	}
	return 0;
}

公约数和

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
//#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int N = 5e6+5,mod=1e9+7;
ll mu[N],pr[N],tot,sum[N];bool is[N];
ll n,m,g[N],k;
ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=ans*a%mod;
		b>>=1;a=a*a%mod;
	}
	return ans;
}
void getMu(int n)
{
	mu[1]=1;
	for(int i=2;i<=n;i++)
	{

		if(!is[i])
		{
			pr[++tot]=i;mu[i]=-1;
		}
		for(int j=1;j<=tot&&pr[j]*i<=n;j++)
		{
			is[pr[j]*i]=1;
			if(i%pr[j]==0)
			{
				g[pr[j]*i]=g[i]*(g[pr[j]]+1)%mod;
				break;
			}
			mu[pr[j]*i]=-mu[i];
		}
	}
	for(int i=1;i<=n;i++)sum[i]=(sum[i-1]+mu[i]);

}
ll solve(ll n,ll d)
{
	ll l=1,r=0;
	n/=d;
	ll res=0;
	while(l<=n)
	{
		r=n/(n/l);
		res=(res+(sum[r]-sum[l-1])*(n/l)*(n/l));
		l=r+1;
	}
	return res;
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n;
	getMu(n);
	ll ans=0;
	for(int d=1;d<=n;d++)
	{
		ans+=d*solve(n,d);
	}
	cout<<(ans-(n*(n+1))/2)/2;
	return 0;
}

P1829 [国家集训队] Crash的数字表格 / JZPTAB

式子好推,不过测试点造的很强,每个括号都不能落下

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
using namespace std;
#define int long long
const ll N=1e7+5,mod=20101009 ;
ll a,b;
bool is[N];ll pr[N],mu[N],tot,sum[N];
ll f[N],n,m;
void getMu(int n)
{
	mu[1]=1;f[1]=1;
	for(ll i=2;i<=n;i++)
	{
		if(!is[i])
		{
			pr[++tot]=i;mu[i]=-1;
			f[i]=(1-i)%mod;
		}
		for(int j=1;j<=tot&&i*pr[j]<=n;j++)
		{
			is[i*pr[j]]=1;
			if(i%pr[j]==0)
			{
				f[i*pr[j]]=f[i];
				break;
			}
			mu[i*pr[j]]=-mu[i];
			f[i*pr[j]]=f[i]*f[pr[j]]%mod;
			// f[i*pr[j]]=max<ll>(1,f[i]);
		}
	}
	for(ll i=1;i<=n;i++)
	{
		sum[i]=(sum[i-1]+1ll*f[i]*i%mod)%mod;
		sum[i]%=mod;
		// if(i<=1e4)cout<<sum[i]<<" ";
	}
}
ll S(ll x)
{
	return (x*(x+1)/2)%mod;
}
ll solve(ll n,ll m)
{
	if(n>m)swap(n,m);
	ll l=1,r;ll ans=0;
	while(l<=n)
	{
		r=min(n/(n/l),m/(m/l));
		ans+=1ll*((sum[r]-sum[l-1]+mod)%mod)*((S(n/l)*S(m/l))%mod)%mod;//这里不括括号的话会炸掉,优先级算完一步就取一次模
		ans=(ans+mod)%mod;
		// cout<<ans<<endl;
		l=r+1;
	}
	return ans;
}
signed main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	// int T;
	// cin>>T;
	getMu(1e7);
	// cout<<"*******"<<endl;
	cin>>n>>m;
	// cout<<n<<" "<<m<<endl;
	cout<<(solve(n,m)+mod)%mod<<endl;
	return 0;
}

DZY LOVES MATH

image

posted @ 2024-07-30 09:04  wlesq  阅读(35)  评论(5编辑  收藏  举报