【powerful number】JZOJ6785.【NOI2020.08.07模拟】T3(remapping)

Description

  • x = ∏ p k x=\prod p^k x=pk,则 f ( x ) = 2 ∑ k f(x)=2^{\sum k} f(x)=2k,求 ∑ 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)=2k2(k2)
  • 那么答案就是 ∑ 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[iabn]=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<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#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);
}

猜你喜欢

转载自blog.csdn.net/qq_43649416/article/details/107874092