2018SD省队集训R2 D5

T2

这里写图片描述

题解

前排鸣谢LCR小姐姐QAQ

首先暴力欧拉筛模拟这个过程就是27pts的

70pts就是化柿子+卡常数

我们可以发现 f(n)=(px11+1)(px22+1)...(pxkk+1) f ( n ) = ( p 1 x 1 + 1 ) ( p 2 x 2 + 1 ) . . . ( p k x k + 1 )

那么他的形式就大概是 f(a1)f(a2)...f(ak) f ( a 1 ) f ( a 2 ) . . . f ( a k ) 类似这个样子,然后我们可以枚举 f(ij)=f(i)f(j) f ( i j ) = f ( i ) f ( j ) ,只要ij<=n那么就是我们要求的答案的一部分,即f(ij),容斥一下答案也就是 ab<=n[(a,b)=1]a ∑ a b <= n [ ( a , b ) = 1 ] a

化个柿子

i=1nij=1ni[(i,j)=1] ∑ i = 1 n i ∑ j = 1 ⌊ n i ⌋ [ ( i , j ) = 1 ]

然后反演
=i=1nij=1nid|(i,j)μ(d) = ∑ i = 1 n i ∑ j = 1 ⌊ n i ⌋ ∑ d | ( i , j ) μ ( d )

套路的枚举d
=d=1nμ(d)d|iinid = ∑ d = 1 n μ ( d ) ∑ d | i i ⌊ ⌊ n i ⌋ d ⌋

i可以枚举d的倍数即i=id
=d=1nμ(d)i=1ndidnidd = ∑ d = 1 n μ ( d ) ∑ i = 1 ⌊ n d ⌋ i d ⌊ ⌊ n i d ⌋ d ⌋

=d=1nμ(d)i=1ndidnd2i = ∑ d = 1 n μ ( d ) ∑ i = 1 ⌊ n d ⌋ i d ⌊ ⌊ n d 2 ⌋ i ⌋

我们可以发现当d^2>n的时候这个值是0了,没有意义,而且当i>n/d^2的时候后面的柿子也是0,那么
=d=1nμ(d)i=1nd2idnd2i = ∑ d = 1 n μ ( d ) ∑ i = 1 ⌊ n d 2 ⌋ i d ⌊ ⌊ n d 2 ⌋ i ⌋

这样加上分块优化可以获得60+的好成绩QAQ(其实剩下的是被卡常了

然后100pts的话
前排鸣谢zyb dalao

ab<=na[(a,b)==1] ∑ a b <= n a [ ( a , b ) == 1 ]

然后我们可以强制a < b,这样只要在后面加的时候加上a,b就好了
a=1nb=a+1na(a+b)[(a,b)==1] ∑ a = 1 n ∑ b = a + 1 n a ( a + b ) [ ( a , b ) == 1 ]

然后莫比乌斯反演

a=1nb=a+1na(a+b)d|(a,b)μ(d) ∑ a = 1 n ∑ b = a + 1 n a ( a + b ) ∑ d | ( a , b ) μ ( d )

d=1ndμ(d)a=1ndb=a+1nad2a+b ∑ d = 1 n d μ ( d ) ∑ a = 1 n d ∑ b = a + 1 n a d 2 a + b

(当然d是从后面的a+b提出来的,因为后面的a,b枚举的都是d的倍数了)

最后一个Σ是O(1)的,前面的是标准的 O(nlogn) O ( n l o g n ) 卡完常数之后可以通过此题

卡常技巧:在%mod的时候,可以开一个unsigned longlong,每8次取一次%,这样似乎会快很多QAQ

代码

#include <cstdio>
#include <iostream>
#include <cmath>
#define LL long long 
#define uli unsigned long long
using namespace std;
const int N=10000005;
const LL INF=8e18;
int mod,mu[N],pri[N],tot;bool ss[N];LL n,up;
void pre()
{
    mu[1]=1;
    for (int i=2;i<=up;i++)
    {
        if (!ss[i]) pri[++tot]=i,mu[i]=-1;
        for (int j=1;j<=tot && pri[j]*i<=up;j++)
        {
            ss[pri[j]*i]=1;
            if (i%pri[j]==0) break;
            mu[pri[j]*i]=-mu[i];
        }
    }
}
LL ksm(LL a,LL k)
{
    LL ans=1;
    for (;k;k>>=1,a=a*a%mod)
      if (k&1) ans=ans*a%mod;
    return ans;
}
int main()
{
    freopen("sum.in","r",stdin);
    freopen("sum.out","w",stdout);
    scanf("%lld%d",&n,&mod);
    up=sqrt(n);pre();LL ans=0;
    for (LL d=1;d<=up;d++)
      if (mu[d])
      {
        LL ok=0;LL sb=up/d,lx=n/d/d;
        for (LL a=1;a<=sb;a++)
        {
            LL t=lx/a%mod;
            ok+=(uli)(t-a)*(t+a*3+1);
            if (ok>INF) ok%=mod;
        }
        ans+=ok%mod*d*mu[d]%mod;
      }
    ans=ans%mod*ksm(2,mod-2)%mod;
    ans++;
    printf("%lld",(ans+mod)%mod);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值