Description
- 若 x = ∏ p k x=\prod p^k x=∏pk,则 f ( x ) = 2 ∑ k f(x)=2^{\sum k} f(x)=2∑k,求 ∑ i = 1 n f ( i ) \sum_{i=1}^nf(i) ∑i=1nf(i)。
- n < = 1 e 14 n<=1e14 n<=1e14
Solution
- 首先 f ( x ) f(x) f(x)是一个积性函数,我们考虑将 f f f卷两次 μ \mu μ。
- u = ( f ∗ μ ) ∗ μ u=(f*\mu)*\mu u=(f∗μ)∗μ(狄利克雷卷积),展开后不难发现 u u u只在powerful number处有值,显然 u u u是一个积性函数,根据这题的条件算出 u ( p k ) = 2 k − 2 ( k ≥ 2 ) u(p^k)=2^{k-2}(k\ge2) u(pk)=2k−2(k≥2)
- 那么答案就是 ∑ i = 1 n u ( i ) ∑ a , b [ i a b ≤ n ] = ∑ i = 1 n u ( i ) ∑ j = 1 n / i d ( j ) \sum_{i=1}^nu(i)\sum_{a,b}[iab\le n]=\sum_{i=1}^nu(i)\sum_{j=1}^{n/i}d(j) ∑i=1nu(i)∑a,b[iab≤n]=∑i=1nu(i)∑j=1n/id(j), d ( i ) d(i) d(i)为 i i i的约数个数。
- ∑ i = 1 m d ( i ) = ∑ i = 1 m m i \sum_{i=1}^{m}d(i)=\sum_{i=1}^{m}\frac{m}{i} ∑i=1md(i)=∑i=1mim,可以 n \sqrt n n 算出。
- powerful number可以表示成 a 2 b 3 a^2b^3 a2b3,不难算出最多有 n \sqrt n n 个,暴力枚举即可。
- 由于是根号套根号,积分后可以算出时间复杂度为 n l o g n \sqrt n\ log\sqrt n n logn
- 注意卡常,我们在计算约数个数的时候,由于对称性可以这样算:
2 ( ∑ i = 1 n n i ) − ( n ) 2 2(\sum_{i=1}^{\sqrt n}\frac{n}{i})-(\sqrt n)^2 2(∑i=1n in)−(n )2,相比整除分块少了4倍的常数。
#include
#include
#include
#include
#define maxn 10000005
#define ll long long
using namespace std;
ll n,sqrp[maxn],_2[60];
int mo;
int tot,pri[maxn],bz[maxn];
void getpri(){
for(int i=2;i<maxn;i++) {
if (!bz[i]) pri[++tot]=i,sqrp[tot]=(ll)i*i;
for(int j=1;pri[j]*i<maxn;j++){
bz[i*pri[j]]=1;
if (i%pri[j]==0) break;
}
}
}
ll s[2][maxn],B,ans;
void doit(ll m,ll mul){
ll p=n/m;
int t=p>B,k=t?n/p:p;
if (s[t][k]) {ans+=mul*s[t][k];return;}
ll sum=0,pb=sqrt(p);
for(int i=1;i<=pb;i++) sum+=p/i;
sum=((sum<<1)-pb*pb)%mo;
s[t][k]=sum,ans+=mul*sum;
}
void dg(ll now,int pre,int cnt){
for(int i=pre+1;i<=tot&&sqrp[i]*now<=n;i++){
ll tmp=now*sqrp[i]; int tmpc=cnt;
while (sqrp[i+1]<=n/tmp)
dg(tmp,i,tmpc),tmp=tmp*pri[i],tmpc++;
tmp=now*sqrp[i],tmpc=cnt,doit(tmp,_2[tmpc]);
while (pri[i]<=n/tmp) tmp=tmp*pri[i],tmpc++,doit(tmp,_2[tmpc]);
}
}
int main(){
freopen("remapping.in","r",stdin);
freopen("remapping.out","w",stdout);
scanf("%lld%d",&n,&mo),B=sqrt(n);
_2[0]=1;for(int i=1;i<60;i++) _2[i]=_2[i-1]*2%mo;
getpri();
doit(1,1),dg(1,0,0);
printf("%lld\n",ans%mo);
}