Sumdiv Page17 分治/逆元

Sumdiv Page17 分治/逆元

书上的分治方法就不提了

加深一下这题的数论解法

先将A做唯一分解

对于 p 1 b k 1 − 1 p 1 − 1 % 9901 {{p_1^{bk_1}-1}\over p_1-1}\%9901 p11p1bk11%9901,可以求出 p 1 − 1 p_1-1 p11在模 9901 9901 9901意义下的逆元(由于 p 1 p_1 p1肯定是个质数,所以可以用费马小定理求解逆元)

但是有逆元的前提是 p 1 − 1 p_1-1 p11 9901 9901 9901互质,由于 9901 9901 9901本身是个质数,所以他们两个数不互质的数学表达式为 ( p 1 − 1 ) % 9901 = 0 ({p_1-1})\%9901=0 (p11)%9901=0。这种情况下的处理为将等比公式还原回去,即计算 ( 1 + p 1 + p 1 2 + . . . p 1 b k 1 ) % m o d (1+p_1+{p_1}^2+...{p_1}^{bk_1})\%mod (1+p1+p12+...p1bk1)%mod,由于 p 1 % 9901 = 1 , p 1 2 % 9901 = p 1 % 9901 × p 1 % 9901 = 1 × 1 = 1 , . . . p 1 b k 1 % 9901 = 1 p_1\%9901=1,{p_1}^2\%9901=p_1\%9901×p_1\%9901=1×1=1,...{p_1}^{bk_1}\%9901=1 p1%9901=1,p12%9901=p1%9901×p1%9901=1×1=1,...p1bk1%9901=1,故其结果为 b k 1 + 1 bk_1+1 bk1+1 1 1 1相加

代码

#define ll long long
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define WW(x) printf("%lld\n",x)
const ll mod=9901;
int mm,a,b;
struct node
{
    ll x,num;
}p[maxn];
ll qpow(ll a,ll b,ll mod)
{
    ll res=1;
    while(b)
    {
        if (b&1)res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}
void solve(int x)
{
    rep(i,2,int(sqrt(x)))
    {
        if (x%i==0)
        {
            ll num=0;
            while(x%i==0)
            {
                x/=i;num++;
            }
            p[mm].x=i;
            p[mm++].num=num;
        }
    }
    if (x>1)
    {
        p[mm].x=x;
        p[mm++].num=1;
    }
}
int main()
{
    while(~scanf("%d%d",&a,&b))
    {
        mm=0;
        solve(a);
        ll ans=1;
        repp(i,0,mm)
        {
            ll x=p[i].x;
            ll num=p[i].num;
            if ((x-1)%mod==0)
            {
                ans=ans*(1+b*num)%mod;
            }
            else
            {
                ll inv=qpow(x-1,mod-2,mod);
                ll pow=qpow(x,b*num+1,mod)-1;
                ans=ans*pow%mod*inv%mod;
            }
        }
        while(ans<0)ans+=mod;
        WW(ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这道题目是求一个表达式的结果,表达式中包含了欧拉函数和向下取整操作。需要注意的是,最后结果需要对一个给定的mod取模。 首先,我们可以把这个表达式分成两部分来计算。第一部分是计算φ(i)的前缀和,第二部分是计算⌊n/i⌋的前缀和。 对于第一部分,我们可以使用线性筛法来计算φ(i)的前缀和。具体步骤如下: 1. 初始化一个数组phi,大小为k+1,用来保存欧拉函数的值。 2. 初始化一个数组prime,用来保存质数。 3. 初始化一个数组isPrime,大小为k+1,用来标记是否是质数。 4. 初始化一个数组sumPhi,大小为k+1,用来保存φ(i)的前缀和。 5. 遍历2到k的每个数i,如果isPrime[i]为true,则将i加入到prime数组中,并且令phi[i] = i-1。 否则,找到i的最小质因数p,令phi[i] = phi[i/p] * p / (p-1)。 6. 遍历prime数组中的每个质数p,更新phi数组中所有p的倍数的值,令phi[i] = phi[i] * p / (p-1)。 7. 计算sumPhi数组的前缀和,即sumPhi[i] = sumPhi[i-1] + phi[i]。 对于第二部分,我们可以使用容斥原理来计算⌊n/i⌋的前缀和。具体步骤如下: 1. 初始化一个数组sumDiv,大小为k+1,用来保存⌊n/i⌋的前缀和。 2. 遍历1到k的每个数i,计算sumDiv[i] = sumDiv[i-1] + ⌊n/i⌋。 3. 使用容斥原理,减去所有的sumDiv[i] * φ(i),其中i为k的因子。 最后,将第一部分和第二部分的结果相乘,并对mod取模,即可得到最终结果。 以上就是求解这道题目的思路和步骤。希望对你有帮助!如果有任何疑问,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值