HDU 5728 PowMod 欧拉函数 递归


感觉智商被掏空…


原题见HDU 5728

定义 k=mi=1φ(i·n) mod 1000000007
n 是无质因子平方项的数.
ans=kkkk...k( mod p),其中k有无穷多个
数据范围: 1n,m,p107


各种引理

  1. 若素数p满足 p2n ,则 φ(n)=p·φ(np) 见性质3
  2. 若素数p满足 pn, p2n ,则 φ(n)=(p1)·φ(np)
  3. abaφ(p)+b%φ(p)(modp)
    gcd(a,p)=1 ,有欧拉定理 aφ(p)1(modp) ,等式成立。
    gcd(a,p)=g>1 ,只要证 aφ(p)a2φ(p)(modp) ,即可得到 aφ(p)aφ(p)
    只要证 aφ(p)(aφ(p)1)=p()
    a=gx,p=gy,gcd(x,y)=1 ,有 gaφ(p)
    φ(y)φ(p)yaφ(y)1aφ(p)1 即证(*)成立。
    aφ(p)01(modp)

分析

题意很清晰啦。数据范围这么大,肯定要先化简。
n 是无质因子平方项的数.这个条件很关键,说明任取n中的因子g,满足gcd(g,ng)=1()
取i,满足 gcd(i,n)=g ,则 gcd(ig,ng)=1 ,综合 ()gcd(g2×ig,ng)=1
则由 φ(i·n)=φ(i·g·ng)=φ(i·g)φ(ng)
gi ,则 φ(i·g)=g·φ(i)

i=1mφ(i·n)===gni=1mg·φ(i)φ(ng)[gcd(i,n)=g]gng·φ(ng)i=1mφ(i)[gcd(i,n)=g]gng·φ(ng)i=1m/gφ(i·g)[gcd(i,n)=1]

然后…莫比乌斯反演展开…并没有什么卵用

所以看了题解,不按套路啊…

任取n中的质数p,若 pi ,则 p2i·n ,则由引理1: φ(i·n)=p·φ(i·np)
pi ,则 p2i·n ,则由引理2: φ(i·n)=(p1)φ(i·np)

i=1mφ(i·n)==p1==pi,i=1mp·φ(i·np)+pi,i=1m(p1)φ(i·np)pi,i=1m(p1+1)·φ(i·np)+pi,i=1m(p1)φ(i·np)pi,i=1mφ(i·np)+(p1)i=1mφ(i·np)i=1m/pφ(i·n)+(p1)i=1mφ(i·np)

S(n,m)=i=1mφ(i·n) ,则
S(n,m)=S(n,mp)+(p1)S(np,m)

处理一下欧拉函数前缀和,递归处理即可。
已经询问过的S(n,m)可以保存在 map<pair<n,m>, S>里,不用反复查询。

然后看看 ans=kkkk...k( mod p)
两种错误的想法,样例都不能过,不想清楚还是很抓狂…
认为 ans=kans( mod p) 或者 ans=ansk( mod p) 的,就不要玩了。
一般情况下, axax%p(modp)

A(k,p)=kkkk...k( mod p)
由引理3, kbkφ(p)+b%φ(p)(modp) b=kkkk...k ,可得

A(k,p)=kφ(p)+A(k,φ(p))


代码

#include <bits/stdc++.h>
using namespace std;
#define N 10000010
#define LL long long
int MOD = 1000000007;
int num[N], prim[N], phi[N], sum[N];
int pn = 0;
void init(){
    memset(num, -1, sizeof(num));
    phi[0] = phi[1] = 1;
    for(int i = 2;i < N;i++){
        if(num[i]){
            prim[pn++] = i;
            phi[i] = i-1;
        }
        for(int j = 0;j < pn && 1LL*i*prim[j] < N;j++){
            if(i % prim[j] == 0){
                phi[i*prim[j]] = phi[i] * prim[j];
                num[i*prim[j]] = 0;
                break;
            }
            phi[i*prim[j]] = phi[i] * (prim[j] - 1);
            num[i*prim[j]] = 0;
        }
    }
    sum[0] = 0;
    for(int i = 1;i < N;i++)
        sum[i] = 1LL*(sum[i-1] + phi[i]) % MOD;
}
int s(int n, int m){
    if(n == 1)
        return sum[m];
    if(m == 0)
        return 0;
    for(int i = 0;i < pn && prim[i] <= n;i++){
        if(n % prim[i] == 0){
            int p = prim[i];
            return (1LL*(p-1)*s(n/p, m)%MOD + s(n, m/p)%MOD)%MOD;
        }
    }
}
LL poo(LL a, int k, int m){
    LL res = 1;
    while(k){
        if(k & 1LL) res = res*a%m;
        k >>= 1;
        a = a*a%m;
    }
    return res;
}
int A(int k, int p){
    if(p == 1) return 0;
    if(k == 1) return 1;
    return poo(1LL*k%p, phi[p]+A(k, phi[p]), p);
}
int main(){
    init();
    int n, m, p;
    while(~scanf("%d%d%d", &n, &m, &p)){
        int k = s(n, m);
        int ans = A(k, p);
        printf("%d\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值