This page looks best with JavaScript enabled

「Luogu3768」简单的数学题-杜教筛

 ·  ✏️ About  758 words  ·  ☕ 2 mins read · 👀3 views


i=1nj=1nijgcd(i,j)) mod p
其中 n<1010

题解🔗

ans=i=1nj=1nijgcd(i,j)) mod p =d=1ndi=1ndj=1ndijd2[gcd(i,j)==1] =d=1nd3i=1ndj=1ndij[gcd(i,j)==1] 

如果我们令

f(d)=i=1nj=1nij[gcd(i,j)==d] g(d)=d|kf(k)=d2i=1ndj=1ndij g(d)=d2[nd(nd+1)2]2

sum(x)=x(x+1)2,原式化为:

g(d)=d2sum(nd)2

就有:

f(d)=d|kμ(k)g(kd) f(1)=i=1nμ(i)g(i) f(1)=i=1nμ(i)i2sum(ni)2

那么:

ans=d=1nd3i=1ndμ(i)i2sum(ndi)2

枚举 id=T,则有

ans=T=1nsum(nT)2d|Td3μ(Td)×(Td)2 =T=1nT2sum(nT)2d|Tdμ(Td) 

idμ=φ , 所以

ans=T=1nsum(nT)2T2φ(T) 

f(x)=x2φ(x),我们就有
ans=T=1nsum(nT)2f(T)

注意到 nT 只有根号个取值,所以我们想要处理出 f(T) 的前缀和。

杜教筛:

S(n)=i=1nh(i)d=2ng(d)S(nd)

如果我们令 g(n)=n2 ,那么

h(i)=(gf)(i)=d|if(d)g(id)=d|id2φ(d)(id)2 =d|iφ(d)i2=i3 

又因为
i=1ni3=[n(n+1)2]2

所以我们就有

S(n)=i=1nh(i)d=2ng(d)S(nd) =[n(n+1)2]2d=2nd2S(nd) 

综上:

ans=T=1nsum(nT)2f(T) S(n)=[n(n+1)2]2d=2nd2S(nd) 

代码实现一定要多取模…

代码🔗

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int MAXN = 8500000;

ll pow(ll x,ll k,ll p){
  ll ans = 1;
  for(ll i = k;i;i>>=1,x = (x*x)%p) if(i & 1) ans = (ans*x)%p;
  return ans;
}

ll inv(ll x,ll p){return pow(x,p-2,p);}

ll p,n,rev_6,rev_2;
map<ll,ll> s;
ll pre_s[MAXN];

void sieve(){
  static ll prime[MAXN],phi[MAXN],cnt = 0;
  static int vis[MAXN];
  phi[1] = 1;
  for(int i = 2;i<=MAXN-1;i++){
    if(vis[i] == 0){
      prime[++cnt] = i;
      phi[i] = i-1;
    }
    for(int j = 1;i * prime[j] <= MAXN-1 && j<=cnt;j++){
      vis[i*prime[j]] = 1;
      if(i % prime[j] == 0){
        phi[i*prime[j]] = phi[i] * (prime[j]);
        break;
      }
      else{
        phi[i*prime[j]] = phi[i] * (prime[j]-1);
      }
    }
  }
  for(int i = 1;i<=MAXN-1;i++){
    pre_s[i] = phi[i]%p * i % p * i % p;
    pre_s[i] += pre_s[i-1];
    pre_s[i] %= p;
  }
}

ll sum(ll x){x%=p;return x%p *(x+1)%p *rev_2%p;}
ll sums(ll x){x%=p;return x%p *(x+1)%p *(x+x+1)%p *rev_6%p;}

ll S(ll n){
  if(n < MAXN) return pre_s[n];
  if(s.count(n))return s[n];
  ll ans = sum(n)%p;
  ans = ans*ans%p;
  for(ll l = 2,r;l <= n;l = r+1){
    r = (n/(n/l));
    ans -= S(n/l)%p * (sums(r) - sums(l-1)+p)%p;
    ans = ans % p;
  }
  return s[n] = ans % p;
}

void init(){
  scanf("%lld %lld",&p,&n);
  rev_6 = inv(6,p),rev_2 = inv(2,p);
}

ll calc(ll n){
  ll ans = 0;
  for(ll l = 1,r;l <= n;l = r+1){
    r = (n/(n/l));
    ll tmp = (S(r) - S(l-1) + p) % p;
    ll summ = sum(n/l) %p;
    ans += summ%p * summ%p * tmp%p;
    ans %= p;
  }
  return ans;
}

int main(){
  init();
  sieve();
  printf("%lld\n",calc(n));
  return 0;
}

cqqqwq
WRITTEN BY
cqqqwq
A student in Software Engineering.


Comments