zoukankan      html  css  js  c++  java
  • 51Nod1584 加权约数和

    这题其实就是反演一波就好了(那你还推了一下午+一晚上),不过第一次碰到(O(nlog n))预处理分块和式的方法……
    不知为啥我跟唐教主的题解推的式子不太一样……(虽然本质上可能是相同的吧)
    那就写一写好了,顺便骗点访问量(逃

    [egin{align} onumber ext{Let}space A=&sum_{i=1}^nsum_{j=1}^i isigma_1(ij),B=sum_{i=1}^n isigma_1(i^2)\ onumber ext{Then}space Ans=&2A-B\ end{align}]

    [egin{align} onumber A=&sum_{i=1}^nsum_{j=1}^i isigma_1(ij)\ onumber =&sum_{i=1}^nsum_{j=1}^i isum_{p|i}sum_{q|j}[(p,q)=1]frac{pj}q\ onumber =&sum_{d=1}^nmu(d)sum_{i=1}^nsum_{j=1}^i isum _{p|i}sum_{q|j}[d|(p,q)]frac{pj}q\ onumber =&sum_{d=1}^nmu(d)sum_{d|p}pleft(sum_{p|i}i ight)sum_{d|q}sum_{q|j}^i frac j q\ onumber =&sum_{d=1}^nmu(d)sum_{p=1}^{leftlfloorfrac n d ight floor}dpleft(sum_{p|i}^{leftlfloorfrac n d ight floor}di ight)sum_{q=1}^{leftlfloorfrac n d ight floor}sum_{q|j}^i frac{dj}{dq}\ onumber =&sum_{d=1}^nmu(d)sum_{p=1}^{leftlfloorfrac n d ight floor}dpleft(sum_{p|i}^{leftlfloorfrac n d ight floor}di ight)sum_{q=1}^isum_{q|j}^i frac j q\ onumber =&sum_{d=1}^nmu(d)d^2sum_{i=1}^{leftlfloorfrac n d ight floor}ileft(sum_{p|i}p ight)sum_{j=1}^isum_{q|j}frac j q\ onumber =&sum_{d=1}^nmu(d)d^2sum_{i=1}^{leftlfloorfrac n d ight floor}isigma_1(i)sum_{j=1}^isigma_1(j)\ onumber =&sum_{d=1}^nmu(d)d^2sum_{i=1}^{leftlfloorfrac n d ight floor}isigma_1(i)S_{sigma_1}(i) end{align}]

    [egin{align} onumber B=&sum_{i=1}^n isigma_1(i^2)\ onumber =&sum_{i=1}^n isum_{p|i}sum_{q|j}[(p,q)=1]frac{pi}q\ onumber =&sum_{d=1}^nmu(d)sum_{i=1}^n isum_{p|i}sum_{q|j}[d|(p,q)]frac{pi}q\ onumber =&sum_{d=1}^nmu(d)sum_{d|i} isum_{d|p|i}sum_{d|q|j}frac{pi}q\ onumber =&sum_{d=1}^nmu(d)d^2sum_{i=1}^{leftlfloorfrac n d ight floor} isum_{p|i}sum_{q|j}pfrac i q\ onumber =&sum_{d=1}^nmu(d)d^2sum_{i=1}^{leftlfloorfrac n d ight floor} isigma_1^2(i)\ end{align}]

    [Ans=2A-B\=sum_{d=1}^nmu(d)d^2sum_{i=1}^{leftlfloorfrac n d ight floor}isigma_1(i)left(2S_{sigma_1}(i)-sigma_1(i) ight) ]

    到了这里就可以用(O(n))预处理+单次询问(O(sqrt n))的经典做法了,总复杂度(O(n+Tsqrt n))
    但是这样还是有点慢……常数优化到一定程度之后极限数据仍然要跑2s+(卡常技巧不行……逃),看来常数优化玩不了了,只能试试别的做法。
    考虑枚举(d)(k=leftlfloorfrac n d ight floor),并考虑它们能对哪些(n)作出贡献。不难发现,如果(leftlfloorfrac n d ight floor=k),那么一定有(nin[dk,d(k+1))),再稍加观察就能得到每对((d,k))都会对(ge dk)的所有(n)作出贡献,因此枚举所有(d,k)并差分一下,最后求一遍前缀和即可。
    这样就能做到预处理(O(nlog n)),询问(O(1))了,不用卡常也可以过。

    #pragma GCC optimize("Ofast")
    #include<stdio.h>
    #define int unsigned
    using namespace std;
    template<class T>inline void readint(T &v){
    	int x=0;
    	char c=getchar();
    	while(c<48)c=getchar();
    	while(c>47){
    		x=x*10+(c^48);
    		c=getchar();
    	}
    	v=x;
    }
    template<class T>inline void writeint(T x){
    	static int a[25];
    	if(!x)putchar('0');
    	else{
    		int i=0;
    		while(x){
    			a[++i]=x%10;
    			x/=10;
    		}
    		while(i)putchar(a[i--]^48);
    	}
    }
    const int maxn=1000010,p=1000000007;
    void get_table(int);
    bool notp[maxn];
    int prime[maxn],mu[maxn],sigma[maxn],ans[maxn],f[maxn];
    signed main(){
    	get_table(1000000);
    	int T;
    	readint(T);
    	for(int k=1;k<=T;k++){
    		int n;
    		readint(n);
    		putchar('C');
    		putchar('a');
    		putchar('s');
    		putchar('e');
    		putchar(' ');
    		putchar('#');
    		writeint(k);
    		putchar(':');
    		putchar(' ');
    		writeint(ans[n]);
    		putchar('
    ');
    	}
    	return 0;
    }
    void get_table(int n){
    	mu[1]=sigma[1]=1;
    	for(int i=2;i<=n;i++){
    		if(!notp[i]){
    			prime[++prime[0]]=i;
    			mu[i]=-1;
    			sigma[i]=i+1;
    			f[i]=1;
    		}
    		for(int j=1;j<=prime[0]&&i*prime[j]<=n;j++){
    			notp[i*prime[j]]=true;
    			if(i%prime[j]){
    				mu[i*prime[j]]=-mu[i];
    				sigma[i*prime[j]]=(long long)sigma[i]*(prime[j]+1)%p;
    				f[i*prime[j]]=i;
    			}
    			else{
    				if(f[i]==1)sigma[i*prime[j]]=((long long)prime[j]*sigma[i]+1)%p;
    				else sigma[i*prime[j]]=(long long)sigma[i/f[i]*prime[j]]*sigma[f[i]]%p;
    				f[i*prime[j]]=f[i];
    			}
    		}
    	}
    	for(int i=2,sum=1;i<=n;i++){
    		sum+=sigma[i];
    		if(sum>=p)sum-=p;
    		sigma[i]=(long long)i*sigma[i]%p*(2ll*sum-sigma[i]+p)%p;
    	}
    	for(int i=1;i<=n;i++){
    		int t=((long long)i*i%p*(signed)mu[i]+p)%p;
    		for(int j=1;i*j<=n;j++)ans[i*j]=(ans[i*j]+(long long)t*sigma[j])%p;
    	}
    	for(int i=2;i<=n;i++){
    		ans[i]+=ans[i-1];
    		if(ans[i]>=p)ans[i]%=p;
    	}
    }
    
  • 相关阅读:
    Ubuntu下speedtest的安装
    Ubuntu下快速安装LAMP server
    用python3.3爬取图片
    用python3.3结合snmpget截取信息
    开源数据库Postgresql的备份和恢复
    vuedraggable 两个不同结构的数组之间拖拽
    MyBatis 使用另一个 mapper 中的 resultMap 和 sql
    怎样处理从后台传来大量数据的分页操作
    doc命令操纵数据库
    (全)Mac中mysql的root账户初始密码忘记解决办法以及更改
  • 原文地址:https://www.cnblogs.com/hzoier/p/7105009.html
Copyright © 2011-2022 走看看