题目链接:点击这里
题目大意:
哈斯图,设
H
n
H_n
Hn 为
n
n
n 的因子组成的哈斯图,对于任意两个因子
u
,
v
(
u
>
v
)
u,v(u>v)
u,v(u>v) ,
u
,
v
u,v
u,v 之间有边当且仅当
u
=
p
⋅
v
u=p·v
u=p⋅v
例如
H
12
H_{12}
H12 如下图所示:
设
f
(
x
)
f(x)
f(x) 为
H
x
H_x
Hx 的边数和,现在给定一个正整数
n
n
n 求
∑
i
=
1
n
f
(
i
)
\sum_{i=1}^nf(i)
∑i=1nf(i)
题目分析:
对于题目所求的
f
(
x
)
f(x)
f(x) 有如下转移:
f
(
x
)
=
{
e
x
=
p
e
∑
i
=
1
n
∑
e
=
1
e
i
(
e
+
1
)
⋅
f
(
x
p
i
e
)
+
e
⋅
d
(
x
p
i
e
)
x
=
∏
p
i
e
i
f(x)=\begin{cases} e &x=p^e\\ \sum_{i=1}^n\sum_{e=1}^{e_i}(e+1)·f(\frac{x}{p_i^e})+e·d(\frac{x}{p_i^e}) &x=\prod p_i^{e_i} \end{cases}
f(x)={e∑i=1n∑e=1ei(e+1)⋅f(piex)+e⋅d(piex)x=pex=∏piei
对于第二个递推式的理解:
f
(
x
p
e
)
f(\frac{x}{p^e})
f(pex) 中的任意一条边
(
u
,
v
)
(u,v)
(u,v) 的两端可以乘上
p
p
p 的
1
1
1 到
e
e
e 次幂,可以得到
e
e
e 条新边,再由乘法原理算上
f
(
x
p
e
)
f(\frac{x}{p^e})
f(pex) 的贡献就是
(
e
+
1
)
⋅
f
(
x
p
i
e
)
(e+1)·f(\frac{x}{p_i^e})
(e+1)⋅f(piex) 。并且f(i/pe)的每个因子
a
a
a,都可以贡献
e
e
e 条形如
(
p
e
a
,
p
e
−
1
a
)
(p^ea,p^{e-1}a)
(pea,pe−1a) 的边
由于
f
(
p
)
=
1
,
d
(
p
)
=
2
f(p)=1,d(p)=2
f(p)=1,d(p)=2 ,所以我们取完全积性函数
F
(
x
)
=
1
F(x)=1
F(x)=1 做
m
i
n
25
min25
min25 筛
我们知道下式是在
f
(
x
)
f(x)
f(x) 是积性函数的情况下推出的:
S
(
n
,
j
)
=
g
(
n
,
∣
P
∣
)
−
∑
i
=
1
j
−
1
f
(
p
i
)
+
∑
k
=
j
+
1
p
k
2
≤
n
∑
e
=
1
p
k
e
≤
n
f
(
p
k
e
)
(
S
(
⌊
n
p
k
e
⌋
,
k
)
+
[
e
>
1
]
)
S(n,j)=g(n,|P|)-\sum_{i=1}^{j-1}f(p_i)+\sum_{k=j+1}^{p_k^2\le n}\sum_{e=1}^{p^e_k\le n}f(p_k^e)(S(\lfloor \frac{n}{p_k^e} \rfloor,k)+[e>1])
S(n,j)=g(n,∣P∣)−i=1∑j−1f(pi)+k=j+1∑pk2≤ne=1∑pke≤nf(pke)(S(⌊pken⌋,k)+[e>1])
对于当前所求,我们需要同属维护
f
(
x
)
f(x)
f(x) 和
d
(
x
)
d(x)
d(x) 两个函数,式子如下:
S
(
n
,
j
)
=
g
(
n
,
∣
P
∣
)
−
∑
i
=
1
j
−
1
f
(
p
i
)
+
∑
k
=
j
+
1
p
k
2
≤
n
∑
e
=
1
p
k
e
≤
n
(
(
e
+
1
)
S
(
⌊
i
p
k
e
⌋
,
k
)
+
e
(
)
S
d
(
⌊
i
p
k
e
⌋
,
k
)
+
[
e
>
1
]
)
S(n,j)=g(n,|P|)-\sum_{i=1}^{j-1}f(p_i)+\sum_{k=j+1}^{p_k^2\le n}\sum_{e=1}^{p^e_k\le n}((e+1)S(\lfloor \frac{i}{p_k^e} \rfloor,k)+e()S_d(\lfloor \frac{i}{p_k^e} \rfloor,k)+[e>1])
S(n,j)=g(n,∣P∣)−i=1∑j−1f(pi)+k=j+1∑pk2≤ne=1∑pke≤n((e+1)S(⌊pkei⌋,k)+e()Sd(⌊pkei⌋,k)+[e>1])
S
d
(
n
,
j
)
=
2
(
g
(
n
,
∣
P
∣
)
−
∑
i
=
1
j
−
1
f
(
p
i
)
)
+
∑
k
=
j
+
1
p
k
2
≤
n
∑
e
=
1
p
k
e
≤
n
d
(
p
k
e
)
(
S
d
(
⌊
n
p
k
e
⌋
,
k
)
+
[
e
>
1
]
)
S_d(n,j)=2(g(n,|P|)-\sum_{i=1}^{j-1}f(p_i))+\sum_{k=j+1}^{p_k^2\le n}\sum_{e=1}^{p^e_k\le n}d(p_k^e)(S_d(\lfloor \frac{n}{p_k^e} \rfloor,k)+[e>1])
Sd(n,j)=2(g(n,∣P∣)−i=1∑j−1f(pi))+k=j+1∑pk2≤ne=1∑pke≤nd(pke)(Sd(⌊pken⌋,k)+[e>1])
经验: m i n 25 min25 min25 筛可以通过筛积性函数前缀和来辅助计算非积性函数的前缀和
具体细节见代码:
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#define ll long long
#define inf 0x3f3f3f3f
#define int ll
#define endl '\n'
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
using namespace std;
int read()
{
int res = 0,flag = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
{
res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch = getchar();
}
return res*flag;
}
const int maxn = 1e6+5;
const int mod = 1145140019;
const double pi = acos(-1);
const double eps = 1e-8;
int n,cnt,pri[maxn],sq;
int w[maxn],tot,id1[maxn],id2[maxn],g1[maxn];
bool vis[maxn];
void get_pri(int n)
{
for(int i = 2;i <= n;i++)
{
if(!vis[i])
{
pri[++cnt] = i;
}
for(int j = 1;j <= cnt && i*pri[j] <= n;j++)
{
vis[i*pri[j]] = true;
if(i%pri[j] == 0) break;
}
}
}
int qpow(int a,int b)
{
int res = 1;
while(b)
{
if(b&1) res = res*a%mod;
a = a*a%mod;
b >>= 1;
}
return res;
}
const int inv2 = qpow(2,mod-2),inv6 = qpow(6,mod-2);
pair<int,int> S(int i,int j)
{
if(pri[j] >= i) return {0,0};
ll pos = i<=sq ? id1[i] : id2[n/i];
ll res = (g1[pos]-j+mod)%mod;
ll d = 2*res%mod;
for(int k = j+1;k<=cnt && pri[k]*pri[k]<=i;k++) //合数部分贡献
{
ll pe = pri[k];
for(int e = 1;pe <= i;e++,pe = pe*pri[k]) //不能取模
{
auto tmp = S(i/pe,k);
d = (d+(tmp.second+(e>1))*(e+1)%mod)%mod;
res = (res+(e+1)*tmp.first%mod+e*(tmp.second+(e>1))%mod)%mod;
}
}
return {res,d};
}
signed main()
{
get_pri(1e6);
int t = read();
while(t--)
{
n = read(); sq = sqrt(n);
tot = 0;
for(int l = 1,r;l <= n;l = r+1)
{
r = min(n,n/(n/l));
w[++tot] = n/l%mod; //取余方便计算下述的g(n,0)
g1[tot] = (w[tot]-1+mod)%mod;
w[tot] = n/l;
if(w[tot] <= sq) id1[w[tot]] = tot;
else id2[n/w[tot]] = tot;
}
for(int j = 1;j <= cnt;j++) //g(n,j)
for(int i = 1;i<=tot && pri[j]*pri[j]<=w[i];i++)
{
ll tmp = w[i]/pri[j];
ll pos = tmp <= sq ? id1[tmp] : id2[n/tmp];
g1[i] = (g1[i]-(g1[pos]-(j-1)+mod)%mod+mod)%mod;
}
printf("%lld\n",(S(n,0).first)%mod);
}
return 0;
}