The 2019 ACM-ICPC China Shannxi Provincial Programming Contest B. Product(杜教筛+约数)

题意

给你n(n109)n(n\leq 10^9)n(n≤109),m(m2×109)m(m\leq 2\times10^9)m(m≤2×109),p(p2×109)p(p\leq 2\times10^9 )p(p≤2×109),ppp为质数求
i=1nj=1nk=1nmgcd(i,j)[kgcd(i,j)]\prod_{i=1}^n\prod_{j=1}^n\prod_{k=1}^nm^{gcd(i,j)[k|gcd(i,j)]}i=1∏n​j=1∏n​k=1∏n​mgcd(i,j)[k∣gcd(i,j)]
ppp的答案

思路

我们先只考虑指数部分和欧拉降幂那么有
i=1nj=1nk=1ngcd(i,j)[kgcd(i,j)] mod p1\sum_{i=1}^n\sum_{j=1}^n\sum_{k=1}^ngcd(i,j)[k|gcd(i,j)]\ mod\ p-1i=1∑n​j=1∑n​k=1∑n​gcd(i,j)[k∣gcd(i,j)] mod p−1
可以认为k=1ngcd(i,j)[kgcd(i,j)]\sum_{k=1}^ngcd(i,j)[k|gcd(i,j)]k=1∑n​gcd(i,j)[k∣gcd(i,j)]
计算的是gcd(i,j)gcd(i,j)gcd(i,j)*gcd(i,j)的约数个数gcd(i,j)∗gcd(i,j)的约数个数,我们用σ(d)\sigma (d)σ(d)表示ddd的约数个数
那么原式就等于
i=1nj=1ngcd(i,j)σ(gcd(i,j))\sum_{i=1}^n\sum_{j=1}^ngcd(i,j)\sigma(gcd(i,j))i=1∑n​j=1∑n​gcd(i,j)σ(gcd(i,j))
d=gcd(i,j)d=gcd(i,j)d=gcd(i,j)得
d=1ndσ(d)i=1nj=1n[gcd(i,j)==d]\sum_{d=1}^nd\sigma(d)\sum_{i=1}^n\sum_{j=1}^n[gcd(i,j)==d]d=1∑n​dσ(d)i=1∑n​j=1∑n​[gcd(i,j)==d]

d=1ndσ(d)i=1ndj=1nd[gcd(i,j)==1]\sum_{d=1}^nd\sigma(d)\sum_{i=1}^{\left \lfloor\frac{n}{d}\right \rfloor}\sum_{j=1}^{\left \lfloor\frac{n}{d}\right \rfloor}[gcd(i,j)==1]d=1∑n​dσ(d)i=1∑⌊dn​⌋​j=1∑⌊dn​⌋​[gcd(i,j)==1]
考虑后面的部分
i=1ndj=1nd[gcd(i,j)==1]\sum_{i=1}^{\left \lfloor\frac{n}{d}\right \rfloor}\sum_{j=1}^{\left \lfloor\frac{n}{d}\right \rfloor}[gcd(i,j)==1]i=1∑⌊dn​⌋​j=1∑⌊dn​⌋​[gcd(i,j)==1]
可以用莫比乌斯反演做但是这恰好iii和jjj的上限都nnn,可以认为是1n1-n1−n中互质的数对数,考虑每个iii的贡献其实就是φ(i)\varphi(i)φ(i)欧拉函数的值,那么答案就是欧拉函数的前缀和,但是由于iii,jjj的顺序是有影响的然后(1,1)(1,1)(1,1)只计算一次所以有
i=1ndj=1nd[gcd(i,j)==1]=2Φ(nd)1\sum_{i=1}^{\left \lfloor\frac{n}{d}\right \rfloor}\sum_{j=1}^{\left \lfloor\frac{n}{d}\right \rfloor}[gcd(i,j)==1]=2*\Phi(\left \lfloor\frac{n}{d}\right \rfloor)-1i=1∑⌊dn​⌋​j=1∑⌊dn​⌋​[gcd(i,j)==1]=2∗Φ(⌊dn​⌋)−1
其中φ\varphiφ为欧拉函数的和函数
那么原式就转化为
=d=1ndσ(d)(2Φ(nd)1)=\sum_{d=1}^nd\sigma(d)(2*\Phi(\left \lfloor\frac{n}{d}\right \rfloor)-1)=d=1∑n​dσ(d)(2∗Φ(⌊dn​⌋)−1)
然后我们再考虑一下
i=1niσ(i)\sum_{i=1}^ni\sigma(i)i=1∑n​iσ(i)
这个求和
可以把约数函数展开来
=i=1nidi1=\sum_{i=1}^ni\sum_{d|i}1=i=1∑n​id∣i∑​1
那么表示的就是对于每一个iii枚举他的因子有哪些,已知在1n1-n1−n中枚举iii的因子和枚举iii的倍数是等价的那么就有
=d=1ndii=\sum_{d=1}^n\sum_{d|i}i=d=1∑n​d∣i∑​i
iii为ddd的倍数,我们再把后面的展开来
=d=1n(d+2d+3d++ndd)=\sum_{d=1}^n(d+2d+3d+\cdots+\left \lfloor\frac{n}{d}\right \rfloor d)=d=1∑n​(d+2d+3d+⋯+⌊dn​⌋d)
后面就是一个等差数列
=d=1ndnd(nd+1)2=\sum_{d=1}^nd\frac{\left \lfloor\frac{n}{d}\right \rfloor(\left \lfloor\frac{n}{d}\right \rfloor+1)}{2}=d=1∑n​d2⌊dn​⌋(⌊dn​⌋+1)​
Id(n)=i=1niσ(i)Id(n)=\sum_{i=1}^ni\sigma(i)Id(n)=i=1∑n​iσ(i)
原式想用分块优化的话那么有last=nnilast=\frac{n}{\frac{n}{i}}last=in​n​有

=i=last+1n(Id(last)Id(i1))(2Φ(ni)1)=\sum_{i=last+1}^n(Id(last)-Id(i-1))(2*\Phi(\left \lfloor\frac{n}{i}\right \rfloor)-1)=i=last+1∑n​(Id(last)−Id(i−1))(2∗Φ(⌊in​⌋)−1)
Id(n)Id(n)Id(n)可以用线性筛处理一部分(先求每个数的约数个数再求前缀和的时候乘以i),大于的部分就用上面求的分块来处理了,欧拉函数求和用杜教筛即可
求完这个后最后的答案求一个快速幂就可以了,尽量都用int,不然会超时

#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N=10000005;
int mod;
unordered_map<int,int> P;
unordered_map<int,int> D;
bool isP[N];
int prime[N];
int cnt;
int phi[N];
int d[N];
int num[N];
long long inv=500000004;
void init()
{
    phi[1]=d[1]=1;
    for(int i=2; i<N; i++)
    {
        if(!isP[i])
        {
            prime[cnt++]=i;
            phi[i]=i-1;
            d[i]=2;
            num[i]=1;
        }
        for(int j=0; j<cnt&&(ll)i*prime[j]<N; j++)
        {
            isP[i*prime[j]]=true;
            if(i%prime[j])
            {
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
                d[i*prime[j]]=d[i]*d[prime[j]];
                num[i*prime[j]]=1;
            }
            else
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                num[i*prime[j]]=num[i]+1;
                d[i*prime[j]]=d[i]/(num[i]+1)*(num[i*prime[j]]+1);
                break;
            }
        }
    }
    for(int i=1; i<N; i++)
    {
        phi[i]=(phi[i]+phi[i-1])%mod;
        d[i]=((ll)i*d[i]+d[i-1])%mod;
    }
}
int Sum(int x)
{
    if(x<N)return phi[x];
    if(P[x])return P[x];
    int ans=(x+1ll)*x/2%mod;
    for(int i=2,last; i<=x; i=last+1)
    {
        last=x/(x/i);
        ans=(ans-(last-i+1ll)*Sum(x/i)%mod+mod)%mod;
    }
    ans=((ll)ans+mod)%mod;
    P[x]=ans;
    return ans;
}
int Id(int n)
{
    if(n<N) return d[n];
    else if(D[n]) return D[n];
    int ans=0;
    for(int i=1,last; i<=n; i=last+1)
    {
        last=n/(n/i);
        ans=(ans+(last+i)*(last-i+1ll)/2%mod*((n/i*(n/i+1ll)/2)%mod)%mod)%mod;
    }
    D[n]=ans;
    return ans;
}
long long quickmod(long long a,long long b,long long p)
{
    long long ans=1;
    while(b)
    {
        if(b%2==1)
            ans=ans*a%p;
        a=a*a%p;
        b=b/2;
    }
    return ans;
}
int main()
{
    int n,m,p;
    scanf("%d%d%d",&n,&m,&p);
    mod=p-1;
    init();
    int ans=0;
    for(int i=1,last; i<=n; i=last+1)
    {
        last=n/(n/i);
        ans=(ans+(Id(last)-Id(i-1)+mod)%mod*((2ll*Sum(n/i)%mod-1ll+mod)%mod)%mod+mod)%mod;
    }
    printf("%lld\n",quickmod(m,ans,p));
    return 0;
}
/*
1000000000 999999997 98765431
*/
上一篇:计蒜客 39272.Tree-树链剖分(点权)+带修改区间异或和 (The 2019 ACM-ICPC China Shannxi Provincial Programming ContestE.)


下一篇:B.Grid with Arrows-The 2019 ICPC China Shaanxi Provincial Programming Contest