zoukankan      html  css  js  c++  java
  • P3768 简单的数学题

    https://www.luogu.com.cn/problem/P3768
    推式子+杜教筛+整除分块,感觉往 (varphi) 的方向推比往 (mu) 上推要好

    [egin{aligned}sum_{i=1}^nsum_{j=1}^n ijgcd(i,j) &=sum_{i=1}^nsum_{j=1}^n ijsum_{k|gcd(i,j)} varphi(k)\ &=sum_{k}varphi(k)sum_{k|i}^nsum_{k|j}^nij\ &=sum_{k}k^2varphi(k)sum_{i=1}^{lfloorfrac{n}{k} floor}isum_{j=1}^{lfloorfrac{n}{j} floor}j\ &=sum_{k}k^2varphi(k)left(sum_{i=1}^{lfloorfrac{n}{k} floor}i ight)^2\ end{aligned} ]

    然后这个 (left(sum_{i=1}^{lfloorfrac{n}{k} floor}i ight)^2) 可以整除分块并 (O(1)) 求,外面再套一个 (k^2varphi(k)) 用杜教筛算就行了
    至于怎么杜教筛,设 (f=varphi cdot operatorname{Id}^2,g=operatorname{Id}^2),那么就有 (f*g=sum_{d|n} varphi(d)d^2left(frac{n}{d} ight)^2=n^2sum_{d|n} varphi(d)=n^3)
    再设 (s)(f) 的前缀和,根据杜教筛的套路式子,就有:

    [egin{aligned}f(1)s(n) &=sum_{i=1}^ng(i)s(lfloorfrac{n}{i} floor)-sum_{i=2}^ng(i)s(lfloorfrac{n}{i} floor)\ &=sum_{i=1}^n(f*g)(i)-sum_{i=2}^ng(i)s(lfloorfrac{n}{i} floor)\ end{aligned} ]

    由于 (g(i)) 以及 (sum_{i=1}^n(f*g)(i)) 都是很好求的,所以就能直接杜教筛了

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<map>
    #define reg register
    #define LL_INF (long long)(0x3f3f3f3f3f3f3f3f)
    #define INT_INF (int)(0x3f3f3f3f)
    inline long long read(){
    	register long long x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    #define maxn 5000000
    long long n;
    long long mod,inv4,inv6;
    std::map<long long,long long>map;
    int notprime[maxn+6],prime[maxn+6];
    long long phi[maxn+6];
    inline long long power(long long a,long long b){
    	long long ans=1;
    	while(b){
    		if(b&1) ans=ans*a%mod;
    		a=a*a%mod;b>>=1;
    	}
    	return ans;
    }
    inline void pre(int n){
    	phi[1]=1;
    	for(reg int i=2;i<=n;i++){
    		if(!notprime[i]) prime[++prime[0]]=i,phi[i]=i-1;
    		for(reg int x,j=1;i*prime[j]<=n&&j<=prime[0];j++){
    			x=i*prime[j];notprime[x]=1;
    			if(i%prime[j]) phi[x]=phi[i]*(prime[j]-1);
    			else{
    				phi[x]=phi[i]*prime[j];break;
    			}
    		}
    		phi[i]=phi[i]*i%mod*i%mod;
    	}
    	for(reg int i=2;i<=n;i++) phi[i]=(phi[i]+phi[i-1])%mod;
    }
    inline long long S2(long long n){
    	n%=mod;
    	return n*(n+1)%mod*(2*n+1)%mod*inv6%mod;
    }
    inline long long S3(long long n){
    	n%=mod;
    	return n*n%mod*(n+1)%mod*(n+1)%mod*inv4%mod;
    }
    long long get(long long n){
    	if(n<=maxn) return phi[n];
    	if(map.find(n)!=map.end()) return map[n];
    	long long ans=S3(n);
    	for(reg long long l=2,r;l<=n;l=r+1){
    		r=n/(n/l);
    		ans=(ans-get(n/l)*(S2(r)-S2(l-1))%mod+mod)%mod;
    	}
    	map[n]=ans;
    	return ans;
    }
    inline long long work(long long n){
    	long long ans=0;
    	for(reg long long l=1,r;l<=n;l=r+1){
    		r=n/(n/l);
    		ans+=S3(n/l)*(get(r)-get(l-1)+mod)%mod;
    		ans%=mod;
    	}
    	return ans;
    }
    int main(){
    	mod=read();n=read();
    	pre(maxn);
    	inv4=power(4,mod-2);inv6=power(6,mod-2);
    	printf("%lld
    ",work(n));
    	return 0;
    }
    
  • 相关阅读:
    无刷电机控制基本原理
    SPI 串行Flash闪存W25Q128FV 的使用(STM32F407)_软件篇
    CAN总线简介
    RS-232串口特性
    PLSQL 安装教程
    JS 常用正则表达式备忘录
    JS数组去重
    Js中Map对象的使用
    JS操作字符串
    前端小技巧
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/14555842.html
Copyright © 2011-2022 走看看