2026icpc网络赛2 E. Exponent

E. Exponent

题目大意

求模 \(n\) 意义下阶的前缀和,具体而言就是求:

\[\begin{aligned} \sum_{a=1}^n\text{ord}_n(a) \end{aligned} \]

  • \(1\le n\le 10^9\)
  • \(1\le T\le 10^3\)

题解

首先根据阶的基础定义显然只有当 \(a \perp n\) 的时候会产生贡献,因此考虑模 \(n\) 意义下的素性 \(a\),根据阶的定义或者欧拉定理,我们有:

\[\text{ord}_n(a)\vert \varphi(n) \]

因此改为枚举 \(m=\varphi(n)\) 的约数,将答案统计变成:

\[\sum_{d\vert m}df(d) \]

其中 \(f(d)\) 表示贡献为 \(d\) 的次数,形式化的:

\[f(d)=\sum_{a=1}^n[\text{ord}_n(a)=d] \]

这个形式虽然不好求解,但是其定义已经有非常强的反演暗示,按照常规的套路将“贡献恰好为 \(d\)”变成“贡献可以为 \(d\)”,具体而言,设 \(g(d)\) 表示:

\[g(d)=\sum_{a=1}^n[a^d\equiv 1 \pmod n] \]

这个形式十分熟悉,它是高次同余方程解的个数,具体而言:

\[x^d\equiv 1 \pmod n \]

这是经典的,该方程解的个数为:

\[\prod_{p^{c}\parallel n} \begin{cases} 2^{\min(1,\,v_2(d))}\gcd\!\left(d,2^{c-2}\right), & p=2,\ c\ge 3 \\[4pt] \gcd\!\left(d,\varphi(p^{c})\right), & \text{else.} \end{cases} \]

实际上式的证明比这道题更难,因此放在最后,这里先权作引用。观察这个形式很容易发现 \(g(d)\) 对 \(d\) 有不完全积性,那么可以使用欧拉乘积加速卷积过程,进一步考虑。

根据 \(\text{ord}_n(a)\vert \varphi(n)\),容易得到:

\[g(d)=\sum_{e\vert d} f(e) \]

接下来莫比乌斯反演得到:

\[f(d)=\sum_{e\vert d} \mu(e)g(\frac{d}{e}) \]

观察这个式子,首先注意到 \(d\) 的取值是有限制的,必然为 \(m\) 的约数,同时 \(g\) 与 \(\mu\) 均为不完全积性函数,故 \(f=\mu*g\) 也为不完全积性函数,最终要计算的 \(f\cdot \text{id}\) 同样为不完全积性函数,即最终的答案可以表示成卷积形式:

\[\text{Ans}=((f\cdot \text{id})*1)(m) \]

这个形式的做法就相当多了,简单说一下:

首先可以枚举约数,先离线处理出整个 \(g\),对 \(n\) 分解质因数,在 \(\Omicron(\omega(n)\log V)\) 复杂度下单点计算,因为 \(f\) 和 \(g\) 定义在所有 \(m=\varphi(n)\) 的约数集上,所以两者均只有 \(\Omicron(\sigma_0(\varphi(n)))\) 级别,那么直接暴力卷积可以实现 \(\Omicron(\sigma_0(\varphi(n)) \log \sigma_0(\varphi(n)))\) 复杂度,最后暴力根号卷积求单点值。

然而实际上还可以继续优化,我们前文也提到了 \(f\cdot \text{id}\) 呈现不完全积性,那么我们可以直接抛弃在整个约数上求 \(g*\mu\),仅在一小段素数幂上应用反演过程,利用常见的欧拉乘积直接对 \(f\) 加速,具体而言:

\[\begin{aligned} g(p^k)&=1+f(p)+\cdots+f(p^k)\\ f(p^k)&=g(p^k)-g(p^{k-1}) \end{aligned} \]

经典的欧拉乘积:

\[\begin{aligned} \sum_{d\vert m}df(d)&=\prod_{p^c\parallel m}(f(1)+pf(p)+\cdots+p^cf(p^c))\\ &=\prod_{p^c\parallel m}\left(\sum_{k=0}^cp^kf(p^k)\right)\\ \end{aligned} \]

那么这部分的复杂度可以优化到 \(\Omicron(\Omega(\varphi(n))\omega(n)\log n)\),现在瓶颈同样在于质因数分解,不过这部分在这个友好的值域下有很多优化的方法,取决于筛出质数表的大小 \(N\),这里就不探索了。总体复杂度 \(\Omicron(N+T\cdot\pi(n)+T\log^3 n)\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+10;
const int inf=1e9;
vector<int> prim;
vector<vector<int>> primk;
int vis[N],id_prim[N];
pair<vector<int>,vector<int>> get(int n){
    vector<int> p_n,cnt_p_n;
    int tem(n);
    for(auto pr:prim){
        if(pr*pr>n) break;
        if(tem%pr==0){
            int cnt(0);
            for(;tem%pr==0;tem/=pr) cnt++;
            p_n.emplace_back(pr);
            cnt_p_n.emplace_back(cnt);
        }
    }
    if(tem^1LL){
        p_n.emplace_back(tem);
        cnt_p_n.emplace_back(1LL);
    }
    return {p_n,cnt_p_n};
}
int get_phi(int n){
    int ans(n),tem(n);
    while(1){
        
        }
    for(auto pr:prim){
        if(pr*pr>n) break;
        if(tem%pr==0){
            for(;tem%pr==0;tem/=pr);
            ans=ans/pr*(pr-1LL);
        }
    }
    if(tem^1LL){
        ans=ans/tem*(tem-1LL);
    }
    return ans;
}
int gcd(int a,int b){
    return __gcd(a,b);
}
void sol(/* int r */){
    int n,m;
    cin>>n;
    m=get_phi(n);
    int ccnt(0);
    auto [pfacn,pcntn]=get(n);// CRT 分解模数
    auto [pfacm,pcntm]=get(m);// 分解阶
    int ans(1);
    for(int di=0;di<(int)pfacm.size();++di){
        int sum(1);
        for(int k=1;k<=pcntm[di];++k){
            int Gk(1),Fk(1),Fk_(1);
            int pk(pcntm[di]==1?pfacm[di]:primk[id_prim[pfacm[di]]][k]);
            int pk_(pk/pfacm[di]);
            for(int i=0;i<(int)pfacn.size();++i){
                ccnt++;
                if(pfacn[i]*pfacn[i]<=n){
                    if(pfacn[i]==2LL&&pcntn[i]>2ll){
                        Fk*=gcd(pk,2ll)*gcd(pk,primk[id_prim[pfacn[i]]][pcntn[i]-2ll]);
                        Fk_*=gcd(pk_,2ll)*gcd(pk_,primk[id_prim[pfacn[i]]][pcntn[i]-2ll]);
                        continue;
                    }
                    Fk*=gcd(pk,primk[id_prim[pfacn[i]]][pcntn[i]-1ll]*(pfacn[i]-1ll));
                    Fk_*=gcd(pk_,primk[id_prim[pfacn[i]]][pcntn[i]-1ll]*(pfacn[i]-1ll));
                }else{
                    Fk*=gcd(pk,pfacn[i]-1);
                    Fk_*=gcd(pk_,pfacn[i]-1);
                }
            }
            Gk=Fk-Fk_;
            sum+=Gk*pk;
        }
        ans*=sum;
    }
    cout<<ans<<'\n';
}
signed main(){
    for(int i=2;i<=N-10;++i){
        if(!vis[i]){
            id_prim[vis[i]=i]=prim.size();
            prim.push_back(i);
        }
        for(int j=0;j<(int)prim.size()&&prim[j]*i<=N-10;++j){
            vis[i*prim[j]]=prim[j];
            if(i%prim[j]==0) break;
        }
    }
    for(int i=0;i<(int)prim.size();++i){
        vector<int> pk;
        pk.emplace_back(1LL);
        for(int j=prim[i];j<=inf;j*=prim[i]){
            pk.emplace_back(j);
        }
        primk.emplace_back(pk);
    }
    int T(inf);
    cin>>T;
    while(T--) sol();
}
/* 
5
48
2
4
8
16
*/

高次同余方程解的个数

实际上这是该题的关键,这个引理比这道题本身麻烦多了。

首先根据 CRT 可以将模数 \(n\) 分解为不同的素数幂,在不同的素数幂下性状独立,因此我们对每个素数幂 \(p^k\) 研究。

首先我们知道原根存在定理,那么当原根存在时,当前素数幂模自然构成一个阶为 \(m=\varphi(p^k)\) 为循环群,群中元素由原根 \(g\) 构成:\(\{g^k\vert k=0,1,\cdots,m\}\),此时原问题变成求同余方程:

\[kd \equiv 0 \pmod m \]

这个形式可以变成:

\[m\mid kd,\ k\le m \]

设 \(g=\gcd(m,d)\),\(m=pg\),\(d=qg\),进一步由:

\[p\mid kq,\ k\le m \]

此时 \(k\) 的取值个数为:\(\frac{m}{p}=g\)。

接下来特殊处理 \(2\) 的次数大于等于 \(3\) 的幂次,因为此时不存在原根,所以特殊分析此时的群结构:

引理: 任意奇数 \(x\) 都有 \(x^{2^{a-2}}\equiv 1\pmod{2^a}\),即单位群中所有元素的阶都整除 \(2^{a-2}\),严格小于 \(m=2^{a-1}\)。

证明: 用 \(v_2(y)\) 表示 \(y\) 中因子 \(2\) 的个数。对任意奇数 \(x\),

\[x^2-1=(x-1)(x+1) \]

\(x-1\) 与 \(x+1\) 是相邻的两个偶数,其中必有一个被 \(4\) 整除,所以 \(v_2(x^2-1)\ge 3\),即 \(x^2\equiv1\pmod 8\)。

接下来观察赋值随平方的增长。对 \(n\ge2\):

\[x^{2^n}-1=(x^{2^{n-1}}-1)(x^{2^{n-1}}+1) \]

此时 \(x^{2^{n-1}}\) 是奇数的平方,\(x^{2^{n-1}}\equiv1\pmod8\),于是 \(x^{2^{n-1}}+1\equiv2\pmod8\),即 \(v_2(x^{2^{n-1}}+1)=1\)。因此

\[v_2(x^{2^n}-1)=v_2(x^{2^{n-1}}-1)+1 \]

每平方一次,\(2\) 的赋值只增加 \(1\)。结合初值归纳得到 \(v_2(x^{2^n}-1)\ge n+2\)(\(n\ge1\))。取 \(n=a-2\):

\[x^{2^{a-2}}\equiv1\pmod{2^{a}} \]

群的阶 \(m=\varphi(2^a)=2^{a-1}\),而任何元素的阶都到不了 \(2^{a-1}\),所以模 \(2^a\ (a\ge3)\) 的单位群不是循环群。\(\blacksquare\)

直观上,奇素数情形"升阶"的起点是 \(v_p(x-1)=1\),而模 \(2\) 时一开始就被 \(x^2\equiv1\pmod8\) 顶掉两级,永远差那一个 \(2\) 的因子补不上,这是 \(2\) 特殊的根源。

群结构: 虽然没有原根,但结构依然干净:

\[(\mathbb Z/2^a\mathbb Z)^{\times}\cong C_2\times C_{2^{a-2}} \]

取两个生成元 \(-1\) 和 \(5\)。\((-1)^2\equiv1\),所以 \(-1\) 的阶为 \(2\)。而 \(5\equiv1\pmod4\) 使得 \(v_2(5^2-1)=v_2(24)=3\) 恰好取到引理中的下界,于是赋值精确增长:

\[v_2(5^{2^n}-1)=n+2 \]

所以 \(5^{2^n}\equiv1\pmod{2^a}\iff n\ge a-2\),\(5\) 的阶恰好是 \(2^{a-2}\)——\(5\) 正是那个"爬得最快"的元素。两个子群相交平凡:\(5^k\equiv1\pmod4\) 而 \(-1\equiv3\pmod4\),故 \(5^k\not\equiv-1\pmod{2^a}\) 对一切 \(k\) 成立。于是映射

\[(i,j)\longmapsto (-1)^i5^j\pmod{2^a} \]

是 \(C_2\times C_{2^{a-2}}\) 到单位群的单同态,两边元素个数都是 \(2^{a-1}\),故为同构。

解的个数: 设 \(x=(-1)^i5^j\),\(x^d\equiv1\pmod{2^a}\) 拆成两个独立条件:

  • \((-1)^{id}\equiv1\):\(d\) 为偶数时 \(i=0,1\) 均可(\(2\) 种),\(d\) 为奇数时只有 \(i=0\)(\(1\) 种),共 \(2^{\min(1,v_2(d))}\) 种;
  • \(5^{jd}\equiv1\iff jd\equiv0\pmod{2^{a-2}}\):与循环群情形的推导完全一致,\(j\) 的取值个数为 \(\gcd(d,2^{a-2})\)。

相乘得到:

\[\#\{x:x^d\equiv1\pmod{2^a}\}=2^{\min(1,v_2(d))}\gcd(d,2^{a-2}) \]

综合两种情形,模 \(p^c\) 下 \(x^d\equiv1\) 的解数为

\[\begin{cases} \gcd(d,\varphi(p^c)), & p\ \text{为奇素数},\\[4pt] 2^{\min(1,v_2(d))}\gcd(d,2^{c-2}), & p=2,\ c\ge3. \end{cases} \]

由 CRT,各素数幂分支独立相乘即得模 \(n\) 下的总解数。

这都什么玩意。。。

posted @ 2026-09-18 22:52  Melting_Pot  阅读(23)  评论(0)    收藏  举报