2019.11.12模拟赛的B题

今天B题的题解

配合董神讲解食用更佳

先分析一下题目给出的公式吧

根据定义:一个正整数的正约数,是每个质因数的幂次加一之后乘起来。

Q1:如何理解这个公式呢?

  首先明确正整数的正约数的质因数是正整数的一部分。所以我们的正约数就是从正整数的质因数中随便选几个数乘起来

例如: 30 = 2 ∗ 3 ∗ 5 30=2*3*5 30=235

  那么对于每一个质因数我们有选和不选两种选择。那么质因数个数就有 ( 1 + 1 ) ∗ ( 1 + 1 ) ∗ ( 1 + 1 ) = 8 (1+1)*(1+1)*(1+1)=8 (1+1)(1+1)(1+1)=8

Q2:如果同类质因数有多个呢?

例如: 60 = 2 2 ∗ 3 ∗ 5 60=2^2*3*5 60=2235

  不难看出,对于质因数2有3种选择方案,选一个,选两个,不选;排除掉不选的情况,你会发现幂次恰好是我们的选择这个质因数方案数。


  公式理解清楚了之后,我们来想想看如何保证我们的正约数的所有质因数不超过P。

  根据上面对公式的分析,我们不难得出,对于比P小的数,选择方案是不变的,而对于比p大的数的选法实际上只有不选这一种(相当于乘1)。

  例如:求60有多少个正约数所有质因数小于5
  因为 60 = 2 2 ∗ 3 ∗ 5 60=2^2*3*5 60=2235,小于5的质因数有2,3。那么答案就是 ( 2 + 1 ) ∗ ( 1 + 1 ) ∗ 1 = 6 (2+1)*(1+1)*1=6 (2+1)(1+1)1=6

  剩下的就是质因数分解了。但是我们发现这是许多 1 0 5 10^5 105 内的数乘积。完了,搞不了。但没有关系,实际影响到我们的只有他们的质因数而已。也就是我们讨论的数的规模不会超过 1 0 5 10^5 105
  但是询问区间是跳跃着的啊,那没有问题。毕竟是离线询问,我们排个序就完事了。

  乘积的维护我个人选择的是树状数组,跟维护前缀和的概念是差不多的。
但我处理的有点复杂emm(高端代码,是所望于群公)

void merge(int x,int k)
{
	ll tmp=(sum[x]+k)%mod,ni=quick(sum[x],mod-2);//求逆元
	//这里我单独用了个sum来记录x原先的值。
	for (int i=x;i<=Max;i+=lowbit(i)) c[i]=c[i]*ni%mod*tmp%mod;
	sum[x]=tmp;
}
ll Sum(int x)
{
	ll ans=1;
	for (int i=x;i>0;i-=lowbit(i)) ans=ans*c[i]%mod;
	return ans;
}

  到这里,如果你会因数分解的话,这道题就结束了。


  但我觉得应该是许多人不会因数分解。我这里给出的是O(n)的欧拉筛分解(好东西)
  对于一个数 i i i,我们设它其中一个质因数为 p p p 那么 i i i 的质因数分解情况就是在 i / p i/p i/p的分解情况上多了个p。
  我们用欧拉筛先求出质数,以及求出每个数的质因数,然后从2讨论到n即可
(说的似乎有点模糊,我给一下代码片段可能会明晰一点。依旧模糊

for (int i=2;i<=n;i++)
{
	int k=i/p(p就是上面给出的质因数)
    if (k==1) continue(跳过质数情况)
    ····//循环讨论
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值