设 g ( x ) g(x) g(x)为 x x x的可重质因子数目, f ( x ) = 2 g ( x ) f(x)=2^{g(x)} f(x)=2g(x)。
求 ∑ i = 1 n f ( i ) \sum_{i=1}^nf(i) ∑i=1nf(i)
奇怪的数论知识增加了。
介绍一个叫power number的东西。power number是所有的质因子的指数都大于等于 2 2 2的数。
每个power number都可以表示成 a 2 b 3 a^2b^3 a2b3的形式,其中 a , b ∈ Z + a,b\in Z^+ a,b∈Z+
power number的数量是比较少的,所以有没有什么办法将值挂在power number上优化求值呢?
构造数论函数 u u u满足 u ∗ I ∗ I = f u*I*I=f u∗I∗I=f,即 u = f ∗ μ ∗ μ u=f*\mu*\mu u=f∗μ∗μ。容易得知 u u u也是个积性函数,并且手玩可以玩出 u ( p k ) u(p^k) u(pk)( p p p为质数)的表达式。然后就可以发现 u u u只有在power number处有值。
接下来推一下式子: ∑ i = 1 n f ( i ) = ∑ i = 1 n ∑ j u ( j ) ∑ a , b [ j a b = i ] = ∑ j u ( j ) ∑ a , b [ j a b ≤ n ] = ∑ j u ( j ) ∑ a , b [ a b ≤ n j ] \sum_{i=1}^nf(i)=\sum_{i=1}^n\sum_j u(j)\sum_{a,b} [jab=i]=\sum_j u(j)\sum_{a,b} [jab\le n]=\sum_j u(j)\sum_{a,b} [ab\le \frac{n}{j}] ∑i=1nf(i)=∑i=1n∑ju(j)∑a,b[jab=i]=∑ju(j)∑a,b[jab≤n]=∑ju(j)∑a,b[ab≤jn]
记 d ( n ) = ∑ a , b [ a b ≤ n ] d(n)=\sum_{a,b}[ab\le n] d(n)=∑a,b[ab≤n]。
这是一个经典问题。朴素求法是变成 ∑ i ⌊ n i ⌋ \sum_i \lfloor \frac{n}{i}\rfloor ∑i⌊in⌋,整除分块。
然后发现时间卡不过去……
有个小优化:画出函数图像 x y = n xy=n xy=n,我们要求函数图像和 x x x正半轴和 y y y正半轴之间的整点个数。这个东西可以看成一个正方形和两个斜边是弯的三角形。正方形的整点可以 O ( 1 ) O(1) O(1)算,然后求弯的三角形内的整点就可以直接枚举每一行,这里行数是 O ( n ) O(\sqrt n) O(n)的。
形式化地说,就是 2 ∑ i = 1 ⌊ n ⌋ ⌊ n i ⌋ + ⌊ n ⌋ 2 2\sum_{i=1}^{\lfloor \sqrt n \rfloor} \lfloor \frac{n}{i} \rfloor+\lfloor \sqrt n \rfloor ^2 2∑i=1⌊n⌋⌊in⌋+⌊n⌋2
左边的这个东西直接暴力算(不要整除分块!!!)。
(当然还有个更厉害的做法是在SB树上二分来拟合凸包,时间复杂度理论上可以达到 O ( n 1 3 lg n ) O(n^{\frac{1}{3}}\lg n) O(n31lgn))
using namespace std;
#include
#include
#include
#include
#include
#define N 10000000
#define ll long long
ll n,sq,mo;
int p[N+1],np;
bool inp[N+1];
void init(int n){
for (int i=2;i<=n;++i){
if (!inp[i])
p[++np]=i;
for (int j=1;j<=np && i*p[j]<=n;++j){
inp[i*p[j]]=1;
if (i%p[j]==0)
break;
}
}
}
ll calc(int k){return (1ll<=(ll)p[x]*p[x];++x){
ll _k=k;
k/=(ll)p[x]*p[x];
for (int i=2;k;k/=p[x],++i)
dfs(x+1,k,uk*calc(i)%mo);
k=_k;
}
}
int main(){
freopen("remapping.in","r",stdin);
freopen("remapping.out","w",stdout);
scanf("%lld%d",&n,&mo);
sq=sqrt(n);
for (;(sq+1)*(sq+1)<=n;++sq);
init(sq);
memset(d1,255,sizeof(int)*(sq+1));
memset(d2,255,sizeof(int)*(sq+1));
dfs(1,n,1);
printf("%lld\n",ans);
return 0;
}