Description
定义:f(x)=∑d∣n∣μ(d)∣ f(x)=\sum_{d|n}|\mu(d)| f(x)=d∣n∑∣μ(d)∣
F(n,m)=∑i=1mf(in)F(n,m)=\sum_{i=1}^mf(in)F(n,m)=i=1∑mf(in)
答案要求
Ans=F(n,m)Ans=F(n,m)Ans=F(n,m)
n,m≤107n,m\leq10^7n,m≤107
Solution
显然的,f(x)f(x)f(x)是一个积性函数,即f(xy)=f(x)f(y),当gcd(x,y)=1f(xy)=f(x)f(y),当\gcd(x,y)=1f(xy)=f(x)f(y),当gcd(x,y)=1,
又有f(ni)=f(n)f(i)/f(gcd(n,i))f(ni)=f(n)f(i)/f(\gcd(n,i))f(ni)=f(n)f(i)/f(gcd(n,i))
可以将上试改写:
f(ni)=f(n)f(i)/f(gcd(i,n))=f(n)f(i)∗∑T∣n,T∣i1f(T)∑Td∣n,Td∣iμ(d) f(ni)=f(n)f(i)/f(\gcd(i,n))=f(n)f(i)*\sum_{T|n,T|i}\frac{1}{f(T)}\sum_{Td|{n,Td|i}}\mu(d)f(ni)=f(n)f(i)/f(gcd(i,n))=f(n)f(i)∗T∣n,T∣i∑f(T)1Td∣n,Td∣i∑μ(d)
所以
f(ni)=f(n)f(i)∗∑T∣n,T∣i∑d∣T1f(d)μ(Td) f(ni)=f(n)f(i)*\sum_{T|n,T|i}\sum_{d|T}\frac{1}{f(d)}\mu(\frac{T}{d})f(ni)=f(n)f(i)∗T∣n,T∣i∑d∣T∑f(d)1μ(dT)
设g(n)=∑d∣n1f(d)μ(nd)g(n)=\sum_{d|n}\frac{1}{f(d)}\mu(\frac{n}{d})g(n)=∑d∣nf(d)1μ(dn)
所以
f(ni)=f(n)f(i)∗∑T∣n,T∣ig(T) f(ni)=f(n)f(i)*\sum_{T|n,T|i}g(T)f(ni)=f(n)f(i)∗T∣n,T∣i∑g(T)
所以
Ans=f(n)∑d∣ng(d)∑i=1⌊md⌋f(id)=f(n)∑d∣ng(d)F(d,⌊md⌋)Ans=f(n)\sum_{d|n}g(d)\sum_{i=1}^{\lfloor\frac{m}{d}\rfloor}f(id)=f(n)\sum_{d|n}g(d)F(d,\lfloor\frac{m}{d}\rfloor)Ans=f(n)d∣n∑g(d)i=1∑⌊dm⌋f(id)=f(n)d∣n∑g(d)F(d,⌊dm⌋)
对于g(1...n)g(1...n)g(1...n),我们可以在O(nlog(n))O(n\log(n))O(nlog(n))的时间内全部算出,
现在问题就变成了如果快速求F(d,⌊md⌋)F(d,\lfloor\frac{m}{d}\rfloor)F(d,⌊dm⌋),
我们考虑对于一组数据,最暴力的求法复杂度是多少(即暴力循环求和):
∑d=1n⌊md⌋≤107log(107)\sum_{d=1}^n\lfloor\frac{m}{d}\rfloor \leq10^7\log(10^7)∑d=1n⌊dm⌋≤107log(107)
所有我们可以将多组询问中所有的F(d,⌊md⌋)F(d,\lfloor\frac{m}{d}\rfloor)F(d,⌊dm⌋)全部离线,只用O(nlog(n))O(n\log(n))O(nlog(n))的时间便可以全部求出来,
总复杂度:O(nlog(n)+∑D(n))O(n\log(n)+\sum D(n))O(nlog(n)+∑D(n))(D(n)D(n)D(n)表示n的约数个数)
Code
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef long long LL;
const int N=1000500,M=10000500,mo=1e9+7;
int read(int &n)
{
bool q=0;n=0;char ch=' ';
for(;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());
if(ch=='-')ch=getchar(),q=1;
for(;ch<='9'&&ch>='0';ch=getchar())n=(n<<1)+(n<<3)+ch-48;
return q?n=-n:n;
}
int n,m,ans;
int pr[N],mu[M];
bool prz[M];
int f[M],g[M];
int er[101],er1[101];
LL Ans[N];
int a[N];
struct qqww
{
int d,i,m;
}d[N*3];
int d0;
LL ksm(LL q,int w)
{
LL ans=1;
for(;w;w>>=1,q=q*q%mo)if(w&1)ans=ans*q%mo;
return ans;
}
void Pre(int n)
{
mu[1]=1;
fo(i,2,n)
{
if(!prz[i])pr[++pr[0]]=i,mu[i]=-1,f[i]=1;
fo(j,1,pr[0])
{
int t=pr[j]*i;
if(t>n)break;
prz[t]=1;
f[t]=f[i];
if(i%pr[j]==0)break;
f[t]=f[i]+1,mu[t]=-mu[i];
}
}
}
bool PX(qqww q,qqww w){return q.d<w.d||(q.d==w.d&&q.m<w.m);}
int main()
{
int q,w,_;
int SRT=clock();
q=100;
er[0]=1;fo(i,1,q)((er[i]=er[i-1]<<1)>=mo?er[i]-=mo:0);
er1[q]=ksm(er[q],mo-2);
fod(i,q-1,0)((er1[i]=er1[i+1]<<1)>=mo?er1[i]-=mo:0);
Pre(1e7);
int mx=0;
read(_);
fo(I,1,_)
{
a[I]=read(n),read(m);
mx=max(n,mx);
mx=max(m,mx);
for(int i=1;i*i<=n;++i)if(n%i==0)
{
d[++d0].d=i;
d[d0].m=m/i;
d[d0].i=I;
if(i*i==n)continue;
d[++d0].d=n/i;
d[d0].m=m/(n/i);
d[d0].i=I;
}
}
// cerr<<clock()-SRT<<endl;
fo(i,1,mx)if(mu[i])
{
if(mu[i]<0)
{
for(int j=1,k=i;k<=mx;++j,k+=i)((g[k]-=er1[f[j]])<0?g[k]+=mo:0);
}else {
for(int j=1,k=i;k<=mx;++j,k+=i)((g[k]+=er1[f[j]])>=mo?g[k]-=mo:0);
}
}
fo(i,1,mx)f[i]=er[f[i]];
sort(d+1,d+1+d0,PX);
LL t=0,j=1;
// cerr<<clock()-SRT<<endl;
fo(I,1,d0)
{
if(d[I].d!=d[I-1].d)t=0,j=1;
for(;j<=d[I].m;++j)
{
(t+=f[j*d[I].d])>=mo?t-=mo:0;
}
Ans[d[I].i]=(Ans[d[I].i]+t*g[d[I].d])%mo;
}
fo(i,1,_)printf("%lld\n",(Ans[i]*f[a[i]])%mo);
// cerr<<clock()-SRT<<endl;
return 0;
}
本文深入探讨了积性函数的性质及其在数学竞赛中的应用,通过线性筛法快速计算特定积性函数的值。介绍了如何利用预处理和优化技巧,在大规模数据集上高效解决与积性函数相关的问题。
621

被折叠的 条评论
为什么被折叠?



