数论其二

1.数论函数的定义:

指定义域是正整数的函数。

2.积性函数与完全积性函数:

积性函数:若\(a,b\)互质,且\(f(ab)=f(a)f(b)\),那么函数\(f(x)\)是积性函数

完全积性函数:\(\forall a,b\),有\(f(ab)=f(a)f(b)\),那么函数\(f(x)\)是完全积性函数

3.常用的数论函数

\(id_k(n)=n^k,\epsilon(n)=[n==1],\sigma_k(n)=\sum_{d|n}d^k\)

4.欧拉函数:

定义:

\(1\sim n\)中与 \(n\) 互质的数的个数是欧拉函数,记作\(\phi(n)\)

计算式:

若$n=p_1^{c_1}\times p_2^{c_2}\times ...\times p_m^{c_m} $ (\(p_1,p_2...p_m\) 为质数),则:

\[\phi(n)=n\times \frac{p_1-1}{p_1} \times \frac{p_2-1}{p_2} \times ...\times \frac{p_m-1}{p_m} =n\times \Pi_{p\in prime,p|n}(1-\frac{1}{p}) \]

性质:

①:欧拉函数是积性函数,即若\(a,b\)互质,则\(\phi(ab)=\phi(a)\phi(b)\)

②:\(1\sim n\)中与 \(n\) 互质的数的和是 \(\frac{\space n\phi(n)}{2}\)

③:如果 \(p\) 是质数,\(p|n\)\(p^2 |n\),则\(\phi(n)=\phi(n/p)\times p\)

④:如果 \(p\) 是质数,\(p|n\)\(p^2 |n\),则\(\phi(n)=\phi(n/p)\times (p-1)\)

⑤:\(\sum_{d|n}\phi(d)=n\),用卷积表示是\(\phi*I=id\),即欧拉反演

5.欧拉定理和扩展欧拉定理:

欧拉定理:若正整数 \(a,n\) 互质,则\(a^{\phi(n)}\equiv 1(mod\space n)\)

扩展欧拉定理:

若正整数 \(a,n\) 互质,则对于任意正整数 \(b\),有

\[a^b\equiv a^{b\space mod\space\phi(n)}\space(mod\space n) \]

对于不互质的情况,有

\[\begin{cases}a^b\equiv a^{b\space mod\space \phi(n)},b< \phi(n)\\a^b\equiv a^{b\space mod\space \phi(n)+\phi(n)},b\geq \phi(n)\end{cases}(mod\space n) \]

P5091 【模板】扩展欧拉定理

while(b=getchar())
    if(!(b<'0'||b>'9'))
        break;
while(b>='0'&&b<='9'){//处理非常大的数的技巧
    num=num*10+b-'0';
    if(num>=phi)
        num=num%phi,mod=1;//phi表示phi(m)
    b=getchar();
}
if(mod) num+=phi;
printf("%lld\n",fpow(a,num));//fpow为快速幂

P4139 上帝与集合的正确用法

直接应用扩展欧拉定理,然后递归暴算,直到模数为 \(1\) 停止。

long long work(long long mod){
	if(mod==1)
		return 0;
	return f(2,work(phi[mod])+phi[mod],mod);//f为快速幂
}
//主函数中:
while(t--){
	scanf("%d",&n);
	printf("%lld\n",work(n));
}

P2480 [SDOI2010] 古代猪文

一句活题意:求

\[g^{\sum_{d|n}C_n^d}mod\space 999911659 \]

如果\(g=999911659\),那么答案是 \(0\)

否则,因为 \(9999111659\) 是质数,所以 \(g\)\(999911659\) 互质。根据欧拉定理,有:

\[ans=g^{\sum_{d|n}C_n^d(mod\space 999911658)}(mod\space 999911659) \]

关键就是求\(\sum_{d|n}C_n^d(mod\space 999911658)\)。直接求比较困难,因为模数太大,无法应用卢卡斯定理降低复杂度。

考虑将 \(999911658\) 质因数分解,得到 \(2\times 3\times 4679\times 35617\)

可以暴力枚举 \(n\) 的因数,然后用卢卡斯定理分别求出 \(\sum_{d|n}C_n^d\)\(2,3,4679,35617\) 的结果,记为 \(a_1,a_2,a_3,a_4\) ,然后求同余方程组:

\[\begin{cases}x\equiv a_1(mod\space 2)\\x\equiv a_2(mod\space 3)\\x\equiv a_3(mod\space 4679)\\x\equiv a_4(mod\space 35617)\end{cases} \]

就能得到\(\sum_{d|n}C_n^d(mod\space 999911658)\),然后快速幂算出\(ans\)即可。

\(code:\)

signed main(){
    scanf("%lld%lld",&n,&g);
    if(g==999911659){//别忘了特判
        printf("0\n");
        return 0;
    }
    for(int i=1;i<=4;++i)
        pre(p[i],i);//预处理阶乘和阶乘逆元
    for(int i=1;i*i<=n;++i){
        if(n%i==0){
            for(int j=1;j<=4;++j)
                a[j]=(a[j]+dfs(n,i,p[j],j))%p[j];//卢卡斯定理
            if(i*i!=n){
                for(int j=1;j<=4;++j)
                    a[j]=(a[j]+dfs(n,n/i,p[j],j))%p[j];
            }
        }
    }
    for(int i=1;i<=4;++i){
        int tmp;
        exgcd(sum/p[i],p[i],tmp,y);
        tmp=tmp*a[i]%p[i];
        tmp=tmp*(sum/p[i]);
        x+=tmp;
    }
    x=(x+sum)%sum;
    printf("%lld\n",fpow(g,x,mod));
    return 0;
}

P3747 [六省联考 2017] 相逢是问候

回忆一下《上帝与集合的正确用法》,可知:对于一个数,使用题目中的操作,操作一定次数后就会变为一个固定的数。可以证明,操作次数是对数级别的。

所以,类似于区间开方,修改时先暴力修改,直到变成固定的数后,就打上标记,以后不再修改它。

首先设 \(a[i][j]\) 表示第 \(i\) 个数进行 \(j\) 次操作后的值,然后预处理出所有的 \(a[i][j]\)

接下来考虑线段树。线段树除了维护区间和以外,还要维护一个 \(id\)\(id\) 表示该节点代表的区间所有的数都已经操作了 \(j\) 次。特别地, \(id=-1\) 表示该节点代表的区间所有的数的 \(id\) 值不完全相同。

然而,如果直接套用《上帝与集合的正确用法》中的方法处理 \(a[i][j]\) ,复杂度是\(O(nlog^3n)\),会超时。可以对快速幂进行优化,将复杂度优化到\(O(nlog^2n)\)。具体而言,先预处理出 \(fpow1[i](i\in[1,10000])\) 表示 \(c^{i}\)\(fpow2[i]\)表示 \(c^{10000i}\) 。假设我们要计算 \(c^k\) ,那么我们只需要算出 \(x=k/10000,y=k\%10000\) ,就有\(c^k=fpow1[y]\times fpow2[x]\)

\(code:\)

void pre_work(int now){
    ++cnt;
    phi[cnt]=now;int tmp=now;
    for(int i=2;i*i<=now;++i)
        if(tmp%i==0){
            while(tmp!=1&&tmp%i==0)
                tmp/=i;
            phi[cnt]=phi[cnt]/i*(i-1);
        }
    if(tmp!=1)
        phi[cnt]=phi[cnt]/tmp*(tmp-1);
    if(phi[cnt]==1)
        return ;
    pre_work(phi[cnt]);
}
int fpow(int x,int y,int mod){
    int s=x;x=1;bool ok=0;
    while(y){
        if(y&1) x=x*s;
        y>>=1;s=s*s;
        if(s>=mod&&y) ok=1,s%=mod;
        if(x>=mod) ok=1,x%=mod;
    }
    if(x>=mod) ok=1;
    return ok?x%mod+mod:x%mod;
}
void pre_work2(){
    for(int j=1;j<=cnt;++j){
        fpow1[0][j]=fpow2[0][j]=1;
        int tmp=fpow(c,10000,phi[j]);
        bool ok1=0,ok2=0;
        if(c>=2) ok2=1;
        for(int i=1;i<=10000;++i){
            fpow1[i][j]=fpow1[i-1][j]*c;
            if(fpow1[i][j]>=phi[j]||ok1)
                fpow1[i][j]=fpow1[i][j]%phi[j]+phi[j],ok1=1;
            fpow2[i][j]=fpow2[i-1][j]*tmp;
            if(fpow2[i][j]>=phi[j]||ok2)
                fpow2[i][j]=fpow2[i][j]%phi[j]+phi[j],ok2=1;
        }
    }
}
int work(int w,int now,int cnt){
    if(now==cnt+1){
        if(w>=phi[now])
            return w%phi[now]+phi[now];
        return w%phi[now];
    }
    int tmp=work(w,now+1,cnt),x,y;
    x=tmp/10000;y=tmp%10000;
    x=fpow2[x][now]*fpow1[y][now];
    if(x>=phi[now])
        x=x%phi[now]+phi[now];
    return x;
}
void push_up(int u){
    p[u].w=(p[u<<1].w+p[u<<1|1].w)%mod;
    if(p[u<<1].id!=-1&&p[u<<1].id==p[u<<1|1].id)
        p[u].id=p[u<<1].id;
    else p[u].id=-1;
}
void build(int u,int l,int r){
    p[u].l=l;p[u].r=r;
    if(l==r){
        p[u].w=a[l][0];
        return ;
    }
    int mid=(l+r)>>1;
    build(u<<1,l,mid);build(u<<1|1,mid+1,r);
    push_up(u);
}
void add(int u,int l,int r,int w){
    if(p[u].id==cnt-1)
        return ;
    if(p[u].l==p[u].r){
        p[u].id+=w;
        p[u].w=a[p[u].l][p[u].id];
        return ;
    }
    int mid=(p[u].l+p[u].r)>>1;
    if(mid>=l)
        add(u<<1,l,r,w);
    if(mid<r)
        add(u<<1|1,l,r,w);
    push_up(u);
}
int ask(int u,int l,int r){
    if(p[u].l>=l&&p[u].r<=r)
        return p[u].w;
    int mid=(p[u].l+p[u].r)>>1,re=0;
    if(mid>=l)
        re=(re+ask(u<<1,l,r))%mod;
    if(mid<r)
        re=(re+ask(u<<1|1,l,r))%mod;
    return re;
}
signed main(){
    scanf("%lld%lld%lld%lld",&n,&m,&mod,&c);
    for(int i=1;i<=n;++i)
        scanf("%lld",&a[i][0]);
    phi[cnt=1]=mod;
    pre_work(mod);
    phi[++cnt]=1;
    pre_work2();
    for(int i=1;i<=n;++i)
        for(int j=1;j<cnt;++j)
            a[i][j]=work(a[i][0],1,j)%mod;
    build(1,1,n);
    for(int i=1;i<=m;++i){
        scanf("%lld%lld%lld",&opt,&l,&r);
        if(opt==0)
            add(1,l,r,1);
        else
            printf("%lld\n",ask(1,l,r));
    }
    return 0;
}

5.莫比乌斯函数:

定义:

\[\mu(n)=\begin{cases}1,n=1\\(-1)^k,n=p_1p_2...p_k\\0,other\end{cases} \]

莫比乌斯反演:

形式0(因数形式):设 \(F(n)=\sum_{d|n}f(d)\),即 \(F=I*f\) ,则 \(f=\mu*F\)

形式1(倍数形式):设 \(F(n)=\sum_{n|d}f(d)\) ,则 \(f(n)=\sum_{n|d}\mu(\frac{d}{n})f(d)\)

线性求欧拉函数和莫比乌斯函数:

for(int i=2;i<=1e7;++i){
	if(!a[i])
		a[i]=i,p[++tot]=i;
	for(int j=1;j<=tot;++j){
		if(p[j]*i>1e7||p[j]>a[i])
			break;
		a[p[j]*i]=p[j];
	}
}
phi[1]=miu[1]=1;
for(int i=2;i<=1e7;++i){
	int tmp=i/a[i];
	if(tmp%a[i]==0){
		phi[i]=phi[tmp]*a[i];
		miu[i]=0;
	}
	else{
		phi[i]=phi[tmp]*(a[i]-1);
		miu[i]=miu[tmp]*-1;
	}
}

P1390公约数的和

简单莫反题。要求

\[\sum_{i=1}^{n}\sum_{j=i+1}^ngcd(i,j) \]

可以先考虑问题的简化版:

\[\sum_{i=1}^{n}\sum_{j=1}^ngcd(i,j) \]

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

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

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

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

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

\[=\sum_{d=1}^nd\sum_{i=1}^{\lfloor \frac{n}{d}\rfloor}\mu(i)\lfloor \frac{n}{di}\rfloor^2 \]

然后用一个数论分块,就可以求出该柿子。

再考虑题目中要求我们算的柿子,设它为\(ans\)

不难发现\(\sum_{i=1}^{n}\sum_{j=1}^ngcd(i,j)=ans\times 2+\sum_{i=1}^{n}gcd(i,i)=ans\times 2+\frac{n\times (n+1)}{2}\)

然后就能愉快地求出来了。

P1447能量采集

不难发现,题目让我们求的是\(\sum_{i=1}^{n}\sum_{j=1}^{m}2\times gcd(i,j)-n\times m\)

于是就转化成为了上一题。\(ans=2\times \sum_{d=1}^nd\sum_{i=1}^{\lfloor \frac{n}{d}\rfloor}\mu(i)\lfloor \frac{n}{di}\rfloor\lfloor \frac{m}{di}\rfloor -n\times m\)(这里假定\(n>=m\)

YY的GCD

莫反\(+\)一个小优化。先假定\(n>=m\)。仍是按照第一题的方式推柿子,\(ans=\sum_{d=1}^n\sum_{i=1}^{\lfloor \frac{n}{d}\rfloor}\mu(i)\lfloor \frac{n}{di}\rfloor\lfloor \frac{m}{di}\rfloor(d\in prime)\)

然而这样复杂度是\(O(n\space logn)\)的,仍会超时,肿么办?

注意到,数对 \((i,d)\) 相当于枚举了所有乘积小于等于 \(n\) 的数(且后一个数是质数)。令 \(T=i\times d\),考虑枚举每一个 \(T\) 对答案有多少贡献(这是一个套路,后面会经常用):

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

然后发现, \(\sum_{k|T,k\in prime}^{} \mu( \frac{T}{k})\) 是可以预处理的。枚举每一个质数 \(p\) ,然后令它的倍数 \(k\) 加上 \(\mu(\frac{k}{p})\)

\(code:\)

void work(){
	ll r=0,a=n,b=m;
	if(a<b) swap(a,b);
	for(int i=1;i<=b;i=r+1){
		r=min(a/(a/i),b/(b/i));
		if(r>b) r=b;
		ans+=(sum[r]-sum[i-1])*(a/i)*(b/i);//注意是a/i下取整,要加括号 
	}
}
int main(){
	for(int i=1;i<=maxn;++i)
		miu[i]=1;
	for(int i=2;i<=maxn;++i){
		if(!vis[i]){
			p[++tot]=i,miu[i]=-1;
			for(int j=i*2;j<=maxn;j+=i){
				vis[j]=1;
				if(j/i%i==0) miu[j]=0;
				else miu[j]*=-1;
			}
		}
	}
	for(int i=1;i<=maxn;++i)
		for(int j=1;p[j]*i<=maxn&&j<=tot;++j)
			s[i*p[j]]+=miu[i];
	for(int i=1;i<=maxn;++i)
		sum[i]=sum[i-1]+s[i];
	scanf("%lld",&t);
	while(t--){
		scanf("%lld%lld",&n,&m);
		ans=0;
		work();
		printf("%lld\n",ans);
	}
	return 0;
}

P3327约数个数和

前言:一些常用的二级结论:

\[\mu(ij)=\mu(i)\mu(j)[gcd(i,j)==1] \]

\[d(ij)=\sum_{x|i}\sum_{y|j}[gcd(x,y)==1] \]

\[\phi(ij)=\frac{\phi(i)\phi(j)gcd(i,j)}{\phi(gcd(i,j))} \]

推柿子参看题解区

然后令\(F(n)=\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor\),则

\[ans=\sum_{g=1}^{\min(n,m)}\mu(g)\cdot F(\lfloor\frac{n}{g}\rfloor)\cdot F(\lfloor\frac{m}{g}\rfloor) \]

然后用数论分块即可。时间复杂度 \(O(n\space \sqrt n+T\space \sqrt n)\)

\(code;\)

void work(){
    scanf("%lld%lld",&n,&m);
    if(n<m)
        swap(n,m);
    int ans=0;
    for(int i=1,r=0,rr=0;i<=m;i=r+1){
        r=n/(n/i);rr=m/(m/i);//cout<<r<<" "<<rr<<endl;
        r=min(r,min(rr,m));//cout<<m/i<<" "<<m/r<<" "<<n/i<<" "<<n/r<<endl;
        ans+=(miu[r]-miu[i-1])*s[m/i]*s[n/i];
    }
    printf("%lld\n",ans);
}
signed main(){
    scanf("%lld",&t);
    for(int i=2;i<=100000;++i){
        if(a[i]==0)
            p[++tot]=i,a[i]=i;
        for(int j=1;j<=tot;++j){
            if(i*p[j]>100000||a[i]<p[j])
                break;
            a[i*p[j]]=p[j];
        }
    }
    for(int i=1;i<=100000;++i)
        miu[i]=1;
    for(int i=2;i<=100000;++i){
        int tmp=i/a[i];
        if(tmp%a[i]==0)
            miu[i]=0;
        else
            miu[i]=-miu[tmp];
    }
    for(int i=1;i<=100000;++i)
        miu[i]+=miu[i-1];
    for(int i=1;i<=100000;++i){
        for(int j=1,r=0;j<=i;j=r+1){
            r=i/(i/j);
            s[i]+=(r-j+1)*(i/j);
        }
    }
    while(t--)
        work();
    //for(int i=1;i<=100;++i)cout<<miu[i]<<" ";cout<<endl;
    return 0;
}

P3768简单的数学题

利用 \(\phi*I=id\) 可以得到:

\[\sum_{d=1}^{n}F^2(\lfloor \frac{n}{d}\rfloor)\cdot d^2\phi(d) \]

其中 \(F(n)=n\times (n+1)/2\)

其中 \(\sum_{d=1}^{n}F^2(\lfloor \frac{n}{d}\rfloor)\) 可以用数论分块处理,剩下的部分考虑杜教筛。

剩下的部分是 \(d^2\phi(d)\) ,设 \(\sum_{d=1}^{n}d^2\phi(d)\)\(s(n)\) ,考虑构造函数 \(g(n)=n^2\) ,则有:

\[s(n)=\sum_{i=1}^{n}((id^2 \phi)*g)(i)-\sum_{i=2}^{n}id^2(i)s(\lfloor \frac{n}{i}\rfloor) \]

化简得到:

\[s(n)=(\frac {n\times (n+1)}{2})^2-\sum_{i=2}^{n}i^2s(\lfloor \frac{n}{i}\rfloor) \]

P3312数表

先不考虑 \(a\) 的限制,有:

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

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

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

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

\[=\sum_{d=1}^{n}f(d)\sum_{k=1}^{\lfloor\frac{m}{d}\rfloor}\mu(k)\lfloor\frac{n}{dk}\rfloor\lfloor\frac{m}{dk}\rfloor \]

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

(其中 \(f(x)\) 表示 \(x\) 的因数和,可以预处理得到)

接下来考虑 \(a\) 。首先将询问按照 \(a\) 从小到大排序,然后开一个树状数组(其中单点\(i\)表示 \((f*\mu)(i)\) ),每次遇到可以加入树状数组的 \(f(i)\) ,就枚举 \(i\) 的倍数,令 \(ki\) 的单点数值增加 \(f(i)\times\mu(k)\) 。然后在数论分块的时候,如果当前区间为 \([l,r]\) ,就让 \(ans\) 乘以 \([l,r]\) 的区间和。

\(code:\)

bool cmp(node a,node b){
    return a.a<b.a;
}
bool cmp2(node a,node b){
    return a.w<b.w;
}
void add(long long x,long long w){
    while(x<=L)
        c[x]=(c[x]+w)%mod,x+=x&(-x);
}
long long ask(long long x){
    long long re=0;
    while(x)
        re=(re+c[x])%mod,x-=x&(-x);
    return re;
}
long long work(long long n,long long m){
    int ans=0;
    if(n<m)
        swap(n,m);
    for(int i=1,r=0;i<=m;i=r+1){
        r=min(n/(n/i),min(m/(m/i),m));
        ans=(ans+((n/i)%mod*(m/i)%mod*((ask(r)-ask(i-1)+mod)%mod)%mod))%mod;
    }
    return ans;
}
void pre_work(){
	for(int i=2;i<=L;++i){
		if(a[i]==0)
			a[i]=i,prime[++tot]=i;
		for(int j=1;j<=tot;++j){
			if(prime[j]*i>L||prime[j]>a[i])
				break;
			a[i*prime[j]]=prime[j];
		}
	}
	miu[1]=1;
	for(int i=2;i<=L;++i){
		int j=i/a[i];
		if(j%a[i]==0)
			miu[i]=0;
		else
			miu[i]=miu[j]*(-1);
	}
    for(int i=1;i<=tot;++i){
        long long now=prime[i];
        p[now][0]=sum[now][0]=1;
        long long tmp=0;
        while(sum[now][tmp]<=L){
            ++tmp;
            p[now][tmp]=p[now][tmp-1]*prime[i];
            sum[now][tmp]=(sum[now][tmp-1]+p[now][tmp]);
        }
    }
    for(int i=1;i<=L;++i){
        long long tmp=i,cnt=0;
        f[i].w=1;f[i].id=i;
        for(int j=1;j<=tot&&prime[j]*prime[j]<=i;++j){
            cnt=0;
            while(tmp%prime[j]==0)
                tmp/=prime[j],++cnt;
            f[i].w=f[i].w*sum[prime[j]][cnt];
        }
        if(tmp!=1)
            f[i].w=f[i].w*sum[tmp][1];
    }
    sort(f+1,f+L+1,cmp2);
}
signed main(){
    pre_work();
	scanf("%lld",&t);
    for(int i=1;i<=t;++i)
        scanf("%lld%lld%lld",&v[i].n,&v[i].m,&v[i].a),v[i].id=i;
    sort(v+1,v+t+1,cmp);
    for(int i=1,j=1;i<=t;++i){
        while(j<=L&&f[j].w<=v[i].a){
            for(int k=f[j].id;k<=L;k+=f[j].id)
                add(k,f[j].w*miu[k/f[j].id]%mod);
            ++j;
        }
        ans[v[i].id]=work(v[i].n,v[i].m);
    }
    for(int i=1;i<=t;++i)
        printf("%lld\n",ans[i]);
	return 0;
}

P1891疯狂LCM

\(lcm(i,n)\)\(n\times i/gcd(n,i)\) 表示,于是原式化为:

\[n\sum_{d|n}\sum_{i=1}^di[gcd(i,d)==1] \]

引理:\(\sum_{i=1}^ni[gcd(i,n)==1]=\frac{\phi(n)\times n}{2}\)

证明:左边的柿子表示\([1,n]\)中与\(n\)互质的数的和,而\([1,n]\)中与\(n\)互质的数是成对出现的,每一对的和为 \(n\) ,所以与 \(n\) 互质的数的平均值为 \(\frac{n}{2}\) ,和为 \(\frac{\phi(n)\times n}{2}\)

因此,上述柿子就化为:

\[n\sum_{d|n}\frac{\phi(d)\times d}{2} \]

\(f(n)=\sum_{d|n}\frac{\phi(d)\times d}{2}\) ,则 \(f(n)\) 可以预处理得到。外层的 \(i\) 循环到 \(n\) ,内层的 \(j\) 循环到 \(\lfloor \frac{n}{i}\rfloor\) ,每次令 \(f(i\times j)+=\frac{\phi(i)\times i}{2}\) 即可。

P4449 于神之怒加强版

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

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

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

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

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

其中,\(\sum_{d|T}d^k\mu(\frac{T}{d})\) 预处理即可。

P3704 [SDOI2017] 数字表格

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

\[=\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_{i=1}^{\lfloor \frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor \frac{m}{d}\rfloor}\sum_{t|gcd(i,j)}\mu(t)} \]

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

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

其中,\(\prod_{d|T}f_{d}^{\mu(\frac{T}{d})}\) 预处理即可。

posted @ 2023-08-03 20:20  andy_lz  阅读(50)  评论(0)    收藏  举报