首页 > 其他分享 >[51Nod 1227] 平均最小公倍数 (杜教筛)

[51Nod 1227] 平均最小公倍数 (杜教筛)

时间:2023-02-21 10:05:43浏览次数:44  
标签:1227 Prime phi 公倍数 LL ret int 51Nod mod


题目描述

[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数

题目分析

这道题其实是​​[51Nod 1238] 最小公倍数之和题解​​的简化版,或者说是本质…
就直接上公式了

[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_02,则[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_03
[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_04
此处有一个常识
[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_05

  • 证明如下
  • 当时,若[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_06,所以与[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_07互质的数是成对出现,且他们的和为[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_07
  • 再加之[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_09的特殊情况,可得
    [51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_10

继续
[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_11
[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_12
此时就可以用整除分块优化+杜教筛计算[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_13
[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_14
[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_15
注意我们是在杜教筛,不能到这里就把[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_16看做[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_17可求的式子而之后再也不做变换,那样往往会陷入更麻烦的方法或者死胡同里去,接着往下
[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_18
然后套杜教筛即可

虽然在外面套了一层整除分块优化,但由于记忆化的原因,不影响时间复杂度,预处理出一部分[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_19后总复杂度为[51Nod 1227] 平均最小公倍数 (杜教筛)_最小公倍数_20

…有兴趣的可以去了解一下​​[51Nod 1238] 最小公倍数之和题解​​,比这道题恶心点

AC code
#include <cstdio>
#include <cstring>
#include <cmath>
#include <tr1/unordered_map>
#include <algorithm>
using namespace std;
using namespace tr1;
typedef long long LL;
const int inv6 = 166666668;
const int inv2 = 500000004;
const int MAXN = 5e6 + 1;
const int mod = 1e9 + 7;
int Prime[MAXN], phi[MAXN], Cnt;
bool IsnotPrime[MAXN];
LL g[MAXN];
void init()
{
phi[1] = 1;
for(int i = 2; i < MAXN; ++i)
{
if(!IsnotPrime[i])
Prime[++Cnt] = i, phi[i] = i-1;
for(int j = 1; j <= Cnt && i * Prime[j] < MAXN; ++j)
{
IsnotPrime[i * Prime[j]] = 1;
if(i % Prime[j] == 0) { phi[i * Prime[j]] = phi[i] * Prime[j]; break; }
phi[i * Prime[j]] = phi[i] * phi[Prime[j]];
}
}
for(int i = 1; i < MAXN; ++i)
g[i] = (g[i-1] + 1ll * phi[i] * i % mod) % mod;
}
unordered_map<LL, LL> G;
inline LL sum1(LL i, LL j) { return ((i+j)%mod) * ((j-i+1)%mod) % mod * inv2 % mod; }
inline LL sum(LL n)
{
if(n < MAXN) return g[n];
if(G.count(n)) return G[n];
LL ret = (n%mod) * ((n+1)%mod) % mod * ((2*n+1)%mod) % mod * inv6 % mod;
for(LL i = 2, j; i <= n; i=j+1)
{
j = n/(n/i);
ret = (ret - sum(n/i) * sum1(i, j) % mod) % mod;
}
return G[n]=ret;
}

LL solve(LL n)
{
LL ret = n%mod;
for(LL i = 1, j; i <= n; i=j+1)
{
j = n/(n/i);
ret = (ret + ((sum(j)-sum(i-1))%mod) * ((n/i)%mod) % mod) % mod;
}
return ret * inv2 % mod;
}

int main ()
{
LL a, b; init();
scanf("%lld%lld", &a, &b);
printf("%lld\n", ((solve(b)-solve(a-1)) % mod + mod) % mod);
}


标签:1227,Prime,phi,公倍数,LL,ret,int,51Nod,mod
From: https://blog.51cto.com/u_15973510/6075823

相关文章