题目大意
我们可以将字符串
s
s
s 写成
k
p
+
p
′
kp+p'
kp+p′ 的形式(其中
p
′
p'
p′ 是
p
p
p 的前缀),表示将字符串
p
p
p 重复
k
k
k 次后拼接上
p
′
p'
p′ 。定义
s
s
s 的循环次数
v
(
s
)
v(s)
v(s) 为
k
k
k 的最大值。
对所有长度为
n
(
≤
1
0
9
)
n(\le 10^9)
n(≤109) 的 01 串
s
s
s ,求他们的
v
(
s
)
v(s)
v(s) 之和。
思路
记
f
(
i
)
f(i)
f(i) 为长度为
n
n
n 的,最短循环节长度恰好为
i
i
i 的 01 串个数,则
2
x
=
∑
d
∣
x
f
(
d
)
2^x=\sum_{d\mid x}f(d)
2x=d∣x∑f(d)
即
2
x
=
f
∗
I
2^x=f*I
2x=f∗I
或
f
=
2
x
∗
μ
f=2^x*\mu
f=2x∗μ
其中
∗
*
∗ 为 Dirichlet卷积,
I
I
I 为全1函数,
μ
\mu
μ 为Mobius函数。
(注意
x
≤
n
2
x\le \frac{n}{2}
x≤2n 时成立,
x
>
n
2
x>\frac{n}{2}
x>2n 时不一定成立,如10101循环节可以是2, 4, 5)
而答案
a
n
s
=
∑
i
=
1
n
[
n
i
]
f
(
i
)
ans=\sum_{i=1}^n[\frac{n}{i}]f(i)
ans=i=1∑n[in]f(i)
因此,我们只需快速求解
f
(
x
)
f(x)
f(x) 的前缀和,然后利用数论分块即可解决该题。
可以利用杜教筛解决。
杜教筛
参考
S
f
∗
g
(
n
)
=
∑
i
=
1
n
∑
d
∣
i
g
(
d
)
f
(
i
d
)
=
∑
d
=
1
n
g
(
d
)
S
f
(
[
n
d
]
)
S_{f*g}(n)=\sum_{i=1}^n\sum_{d\mid i}g(d)f(\frac{i}{d})=\sum_{d=1}^ng(d)S_f([\frac{n}{d}])
Sf∗g(n)=i=1∑nd∣i∑g(d)f(di)=d=1∑ng(d)Sf([dn])
即
S
f
(
n
)
=
S
f
∗
g
(
n
)
−
∑
d
=
2
n
g
(
d
)
S
f
(
[
n
d
]
)
S_f(n)=S_{f*g}(n)-\sum_{d=2}^ng(d)S_f([\frac{n}{d}])
Sf(n)=Sf∗g(n)−d=2∑ng(d)Sf([dn])
可以先求出
n
2
3
n^\frac{2}{3}
n32的
S
f
(
n
)
S_f(n)
Sf(n) ,对大范围的
S
f
(
n
)
S_f(n)
Sf(n) 用 map 存一下。
若
S
f
∗
g
(
n
)
S_{f*g}(n)
Sf∗g(n) 可以
O
(
1
)
O(1)
O(1) 求解,则总复杂度为
O
(
n
2
3
)
O(n^\frac{2}{3})
O(n32)。
回到本题, S f ( n ) = ( 2 n + 1 − 2 ) − ∑ d = 2 n S f ( [ n d ] ) S_f(n)=(2^{n+1}-2)-\sum_{d=2}^nS_f([\frac{n}{d}]) Sf(n)=(2n+1−2)−∑d=2nSf([dn])
但我们只能求 S f ( d ) ( d ≤ n 2 ) S_f(d) (d\le \frac{n}{2}) Sf(d)(d≤2n) ,剩下的用 2 n 2^n 2n 减去即可。
代码
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define per(i, r, l) for (int i = r; i >= l; --i)
using namespace std;
typedef long long ll;
const int mod = 998244353;
const int N = 1000006;
int pw(int x, int y) {
int ret = 1;
while (y) {
if (y & 1) ret = 1ll * ret * x % mod;
x = 1ll * x * x % mod;
y >>= 1;
}
return ret;
}
int prime[N], tot = 0;
bool iscmp[N];
int mu[N];
int f[N], ss[N];
void init() {
mu[1] = 1;
rep(i, 2, 1000000) {
if (!iscmp[i]) prime[++tot] = i, mu[i] = mod - 1;
for (int j = 1; j <= tot && i * prime[j] <= 1000000; ++j) {
iscmp[i * prime[j]] = 1;
if (i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
} else {
mu[i * prime[j]] = mod - mu[i];
}
}
}
int t = 1;
rep(i, 1, 1000000) {
t = t * 2 % mod;
for (int j = 1; i * j <= 1000000; ++j) {
f[i * j] = (f[i * j] + 1ll * t * mu[j]) % mod;
}
}
rep(i, 1, 1000000) { ss[i] = (ss[i - 1] + f[i]) % mod; }
}
map<int, int> s;
int sum(int n) {
if (n <= 1000000) return ss[n];
if (s.count(n)) return s[n];
int ret = (pw(2, n + 1) - 2 + mod) % mod;
for (int i = 2, last; i <= n; i = last + 1) {
last = n / (n / i);
ret = (ret - 1ll * sum(n / i) * (last - i + 1) % mod + mod) % mod;
}
return s[n] = ret;
}
int solve(int n) {
int ret = 0;
for (int i = 1, last; i <= n / 2; i = last + 1) {
last = n / (n / i);
ret = (ret + 1ll * (sum(last) - sum(i - 1) + mod) * (n / i)) % mod;
}
ret = (1ll * ret + pw(2, n) - sum(n / 2) + mod) % mod;
return ret;
}
int T;
int n;
int main() {
init();
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
printf("%d\n", solve(n));
}
return 0;
}