2018SD省队集训R2 D5

T2

这里写图片描述

题解

前排鸣谢LCR小姐姐QAQ

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

70pts就是化柿子+卡常数

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

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

化个柿子

i = 1 n i j = 1 n i [ ( i , j ) = 1 ]

然后反演
= i = 1 n i j = 1 n i d | ( i , j ) μ ( d )

套路的枚举d
= d = 1 n μ ( d ) d | i i n i d

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

= d = 1 n μ ( d ) i = 1 n d i d n d 2 i

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

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

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

a b <= n a [ ( a , b ) == 1 ]

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

然后莫比乌斯反演

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

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 ( 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);
}

猜你喜欢

转载自blog.csdn.net/blue_cuso4/article/details/80932339
d5
今日推荐