zoukankan      html  css  js  c++  java
  • 【51Nod1584】加权约数和(数论)

    【51Nod1584】加权约数和(数论)

    题面

    51Nod

    题解

    要求的是$$sum_{i=1}nsum_{j=1}n max(i,j)sigma(ij)$$
    这个(max)太讨厌了,直接枚举一半乘个二。

    [2sum_{i=1}^nsum_{j=1}^{i}isigma(ij)-sum_{i=1}^nisigma(i^2) ]

    后面这一半可以直接预处理,只需要把(i)分解,可以做到调和级数的复杂度。
    只考虑前面这一半,显然只需要考虑的是(sigma(ij))这个东西。
    那么我们考虑在(i)中枚举一个约数,在(j)中枚举一个约数,然后把这两个约数合并一下,看看能不能让每个约数只被计算一次。

    [sigma(ij)=sum_{u|i}sum_{v|j}[gcd(u,frac{j}{v})=1]uv ]

    证明的话,大概就是我们的目标是让每个约数只被计算一次,首先在(i)中枚举一个约数肯定没有问题,在(j)中枚举一个质因数也没有问题。对于(uv)这个数而言,我们把只在(i)中有的因子和只在(j)中有的因子给丢掉,只考虑在(i,j)中都含有的因子(u',v'),对于一个数(uv)而言,可能算重的情况是(u')(v')那里抢走了一个质因子,而此时(frac{j}{v})就会对应的乘上那个质因子,使得(gcd eq 1),所以每个数只会被计算一次。
    有了这个式子就很好搞了,首先把这个式子换一个形式:

    [sigma(ij)=sum_{u|i}sum_{v|j}[gcd(u,v)=1]frac{uj}{v} ]

    带回去得到:

    [sum_{i=1}^n isum_{j=1}^isum_{u|i}sum_{v|j}[gcd(u,v)=1]frac{uj}{v} ]

    考虑对于每一个(i)分别计算答案,所以我们设

    [egin{aligned} f[n]&=nsum_{j=1}^nsum_{u|n}sum_{v|j}[gcd(u,v)=1]frac{uj}{v}\ &=nsum_{j=1}^n sum_{u|n}sum_{v|j}frac{uj}{v}sum_{k|u,k|v}mu(k)\ &=nsum_{j=1}^nsum_{k|n,k|j}mu(k)sum_{k|u,u|n}sum_{k|v,v|j}frac{uj}{v}\ &=nsum_{j=1}^nsum_{k|n,k|j}mu(k)(ksigma(frac{n}{k}))sigma(frac{j}{k})\ &=nsum_{k|n}mu(k)ksigma(frac{n}{k})sum_{i=1}^{n/k}sigma(i) end{aligned}]

    然后就是前缀和计算就行了。
    所有东西可以线性筛,中间要求逆就直接快速幂了。。。。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define ll long long
    #define MOD 1000000007
    #define MAX 1000100
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
    bool zs[MAX];
    int pri[MAX],tot;
    int mu[MAX],sig[MAX],ssig[MAX],pw[MAX],spw[MAX],dpw[MAX],dspw[MAX],dsig[MAX];
    int f[MAX],s[MAX];
    void Sieve(int n)
    {
    	mu[1]=1;dsig[1]=sig[1]=1;
    	for(int i=2;i<=n;++i)
    	{
    		if(!zs[i])
    		{
    			pri[++tot]=i,mu[i]=MOD-1;
    			sig[i]=i+1,pw[i]=i,spw[i]=i+1;
    			dsig[i]=dspw[i]=(1+i+1ll*i*i)%MOD;dpw[i]=1ll*i*i%MOD;
    		}
    		for(int j=1;j<=tot&&i*pri[j]<=n;++j)
    		{
    			zs[i*pri[j]]=true;
    			if(i%pri[j])
    			{
    				mu[i*pri[j]]=MOD-mu[i];
    				sig[i*pri[j]]=1ll*sig[i]*sig[pri[j]]%MOD;
    				pw[i*pri[j]]=pri[j],spw[i*pri[j]]=1+pri[j];
    				dsig[i*pri[j]]=1ll*dsig[i]*dsig[pri[j]]%MOD;
    				dpw[i*pri[j]]=dpw[pri[j]];
    				dspw[i*pri[j]]=dspw[pri[j]];
    			}
    			else
    			{
    				mu[i*pri[j]]=0;
    				sig[i*pri[j]]=1ll*sig[i]*fpow(spw[i],MOD-2)%MOD*(spw[i]+pw[i]*pri[j])%MOD;
    				pw[i*pri[j]]=pw[i]*pri[j];
    				spw[i*pri[j]]=(spw[i]+pw[i]*pri[j])%MOD;
    				dspw[i*pri[j]]=(dspw[i]+1ll*dpw[i]*pri[j]%MOD+1ll*dpw[i]*pri[j]%MOD*pri[j]%MOD)%MOD;
    				dsig[i*pri[j]]=1ll*dsig[i]*fpow(dspw[i],MOD-2)%MOD*dspw[i*pri[j]]%MOD;
    				dpw[i*pri[j]]=1ll*dpw[i]*pri[j]%MOD*pri[j]%MOD;
    				break;
    			}
    		}
    	}
    	for(int i=1;i<=n;++i)dsig[i]=1ll*dsig[i]%MOD*i%MOD;
    	for(int i=1;i<=n;++i)ssig[i]=(ssig[i-1]+sig[i])%MOD;
    	for(int i=1;i<=n;++i)
    	{
    		if(mu[i])
    			for(int j=i;j<=n;j+=i)
    				f[j]=(f[j]+1ll*mu[i]*i%MOD*sig[j/i]%MOD*ssig[j/i])%MOD;
    		f[i]=1ll*f[i]*i%MOD;s[i]=(s[i-1]+2ll*f[i]+MOD-dsig[i])%MOD;
    	}
    }
    int main()
    {
    	Sieve(MAX-1);
    	int T=read();
    	for(int i=1;i<=T;++i)
    		printf("Case #%d: %d
    ",i,s[read()]);
    	return 0;
    }
    
  • 相关阅读:
    无线网络中,使用MDK3把指定的用户或者热点踢到掉线
    TCP/IP, UDP, ICMP, ARP协议族简介--纯图慎点
    大数据 Hibernate
    Activiti task claim concurrent
    C++ Java throw goto
    杀死Linux中的defunct进程(僵尸进程)的方法指南
    JQuery selector form input
    帆软 联合 创始人 数据可视化 中国 发展 FineReport FineBI
    Eclipse创建Maven父子项目
    Tomcat Response encode
  • 原文地址:https://www.cnblogs.com/cjyyb/p/11141695.html
Copyright © 2011-2022 走看看