HDU_5528_Count a * b (推式子+积性函数)*

参考一位很牛的大佬博客:https://blog.csdn.net/firstlucker/article/details/49336427

https://www.cnblogs.com/edward108/p/7636856.html








分析:

f ( n ) = n 2 − ∑ i = 0 n − 1 ∑ j = 0 n − 1 n ∣ ( i ∗ j ) = n 2 − ∑ i = 1 n ∑ j = 1 n n ∣ ( i ∗ j ) 注 : 表 明 j 中 含 有 ( n / g c d ( i , n ) ) 这 个 因 子 , 故 = n 2 − ∑ i = 1 n ∑ n g c d ( i , n ) ∣ j , 1 ≤ j ≤ n 1 = n 2 − ∑ i = 1 n n n / g c d ( i , n ) = n 2 − ∑ i = 1 n g c d ( i , n ) 注 : g c d ( i , n ) 可 以 取 的 值 设 为 d , 则 有 d ∣ n , d ∣ i , 令 i = j ∗ d , 故 = n 2 − ∑ d ∣ n ∑ j ∗ d = 1 n d [ g c d ( j ∗ d , n ) = d ] = n 2 − ∑ d ∣ n ∑ j ∗ d = 1 n d [ g c d ( j , n d ) = 1 ] = n 2 − ∑ d ∣ n ∑ j = 1 n d d [ g c d ( j , n d ) = 1 ] = n 2 − ∑ d ∣ n d ∑ j = 1 n d [ g c d ( j , n d ) = 1 ] 后 半 部 分 恰 好 是 φ ( n d ) 的 值 = n 2 − ∑ d ∣ n d φ ( n d ) f(n)=n^2-\sum_{i=0}^{n-1}\sum_{j=0}^{n-1}n|(i*j)\\ =n^2-\sum_{i=1}^n\sum_{j=1}^{n}n|(i*j)\\注:表明j中含有(n/gcd(i,n))这个因子,故\\ =n^2-\sum_{i=1}^n\sum_{\frac{n}{gcd(i,n)}|j,1\leq j \leq n}1\\= n^2-\sum_{i=1}^n\frac{n}{{n}/{gcd(i,n)}}\\=n^2-\sum_{i=1}^ngcd(i,n) \\注:gcd(i,n)可以取的值设为d,则有d|n,d|i,\\令i=j*d,故\\=n^2-\sum_{d|n}\sum_{j*d=1}^nd[gcd(j*d,n)=d]\\=n^2-\sum_{d|n}\sum_{j*d=1}^nd[gcd(j,\frac{n}{d})=1]\\=n^2-\sum_{d|n}\sum_{j=1}^{\frac{n}{d}}d[gcd(j,\frac{n}{d})=1]\\=n^2-\sum_{d|n}d\sum_{j=1}^{\frac{n}{d}}[gcd(j,\frac{n}{d})=1]\\后半部分恰好是\varphi(\frac{n}{d})的值\\=n^2-\sum_{d|n}d\varphi(\frac{n}{d}) f(n)=n2i=0n1j=0n1n(ij)=n2i=1nj=1nn(ij)jn/gcd(i,n)=n2i=1ngcd(i,n)nj,1jn1=n2i=1nn/gcd(i,n)n=n2i=1ngcd(i,n)gcd(i,n)d,dn,di,i=jd,=n2dnjd=1nd[gcd(jd,n)=d]=n2dnjd=1nd[gcd(j,dn)=1]=n2dnj=1dnd[gcd(j,dn)=1]=n2dndj=1dn[gcd(j,dn)=1]φ(dn)=n2dndφ(dn)

接下来计算g(n)
g ( n ) = ∑ m ∣ n f ( n ) = ∑ m ∣ n m 2 − ∑ m ∣ n ∑ d ∣ m d φ ( m d ) 注 : 后 半 部 分 中 的 d 满 足 d ∣ n , 改 变 枚 举 顺 序 , 先 确 定 d , 令 i = m d , 则 m = i ∗ d , 由 于 m ∣ n , 故 ( i ∗ d ) ∣ n , 又 d ∣ n , 所 以 i ∣ n d = ∑ m ∣ n m 2 − ∑ d ∣ n ∑ i ∣ n d d ∗ φ ( i ) = ∑ m ∣ n m 2 − ∑ d ∣ n d ∑ i ∣ n d φ ( i ) 注 : 后 半 部 分 恰 好 是 欧 拉 函 数 的 性 质 : n = ∑ d ∣ n φ ( d ) = ∑ m ∣ n m 2 − ∑ d ∣ n d ∗ n d = ∑ m ∣ n m 2 − ∑ d ∣ n n g(n)=\sum_{m|n}f(n)\\=\sum_{m|n}m^2-\sum_{m|n}\sum_{d|m}d\varphi(\frac{m}{d})\\注:后半部分中的d满足d|n,改变枚举顺序,先确定d,令i=\frac{m}{d},则m=i*d,由于m|n,故(i*d)|n,又d|n,所以i|\frac{n}{d}\\=\sum_{m|n}m^2-\sum_{d|n}\sum_{i|\frac{n}{d}}d*\varphi(i)\\=\sum_{m|n}m^2-\sum_{d|n}d\sum_{i|\frac{n}{d}}\varphi(i)\\注:后半部分恰好是欧拉函数的性质:n=\sum_{d|n}\varphi(d)\\=\sum_{m|n}m^2-\sum_{d|n}d*\frac{n}{d}\\=\sum_{m|n}m^2-\sum_{d|n}n g(n)=mnf(n)=mnm2mndmdφ(dm)ddn,d,i=dm,m=id,mn,(id)n,dn,idn=mnm2dnidndφ(i)=mnm2dndidnφ(i):n=dnφ(d)=mnm2dnddn=mnm2dnn


后 半 部 分 就 是 n 乘 以 n 的 因 子 个 数 , 对 于 前 半 部 分 , 先 考 虑 n 是 一 个 素 因 子 的 幂 的 情 况 , n = p α m 可 以 取 p 0 , p 1 , ⋯   , p α . 那 么 ∑ m ∣ n m 2 = p 0 + p 2 + p 4 + ⋯ + p 2 α 对 于 这 个 等 比 数 列 , 可 以 在 进 行 求 α 的 过 程 中 , 对 其 进 行 累 加 , 或 者 通 过 等 比 数 列 求 和 公 式 进 行 计 算 , 不 过 得 用 到 防 溢 出 操 作 对 于 一 般 的 n = ∏ i = 1 r p i α i , 把 每 个 结 果 相 乘 就 行 ( 积 性 函 数 ) ∑ m ∣ n m 2 = ∏ i = 1 r ( p i 0 + p i 2 + p i 4 + ⋯ + p i 2 α i ) 通 过 这 个 式 子 也 可 以 发 现 n 的 因 子 个 数 就 是 , 每 种 因 子 可 以 有 α + 1 种 选 择 , 然 后 相 乘 就 得 到 n 的 因 子 个 数 最 后 那 个 2 64 说 是 使 用 u n s i g n e d   l o n g   l o n g 运 算 \\后半部分就是n乘以n的因子个数,对于前半部分,\\ 先考虑n是一个素因子的幂的情况,n=p^\alpha\\ m可以取p^0,p^1,\cdots,p^\alpha.\\ 那么\sum_{m|n}m^2=p^0+p^2+p^4+\cdots+p^{2\alpha}\\ 对于这个等比数列,可以在进行求\alpha的过程中,对其进行累加,\\或者通过等比数列求和公式进行计算,不过得用到防溢出操作\\对于一般的n=\prod_{i=1}^rp_i^{\alpha _i},把每个结果相乘就行(积性函数)\\ \sum_{m|n}m^2=\prod_{i=1}^r(p_i^0+p_i^2+p_i^4+\cdots+p_i^{2\alpha_i})\\ 通过这个式子也可以发现n的因子个数就是,每种因子可以有\alpha+1种选择,然后相乘就得到n的因子个数\\最后那个2^{64} 说是使用unsigned \ long \ long 运算 nnnn=pαmp0,p1,,pα.mnm2=p0+p2+p4++p2ααn=i=1rpiαi(mnm2=i=1r(pi0+pi2+pi4++pi2αi)nα+1n264使unsigned long long
复杂度:20000*32左右








对于用等比数列求和的,需要防溢出操作:a,b都比较大,c比较小,计算a*b/c(保证ab%c==0),可以转化为计算:
(a/c)*(b/c)*c+a%c*(b/c)+b%c*(a/c)

#include 

using namespace std;
#define ull unsigned long long 


const int N=1e5+10;
int prime[N];


void get_prime()
{
	for(int i=2;i<N;i++)
	{
		if(!prime[i]){
			prime[++prime[0]]=i;
			
		}
		for(int j=1;j<=prime[0]&& i*prime[j]<N;j++)
		{
			prime[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				break;
			}
		}
	}
}

void solve(ull n)
{
	ull ans=1,res=n;//res记n的因子个数
	int alpha=0;
	for(int i=1;i<=prime[0]&&prime[i]*prime[i]<=n;i++)
	{
		ull tmp=1,alpha=0;
		ull ts=0;//p^2i的和
		ts=tmp;
		if(n%prime[i]==0)
		{
			while(n%prime[i]==0)
			{
				alpha++;
				tmp=tmp*prime[i]*prime[i];
				ts+=tmp;
				n/=prime[i];
			}
			ans=ans*ts;
			res*=(alpha+1);
		}
		
	}
	if(n>1)
	{
		res*=2;
		ans=ans*(1+(ull)n*n);
	}
	printf("%llu\n",ans-res);
}

int main()
{
	get_prime();
	int t;
	ull n;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%llu",&n);
		solve(n);
	}
    return 0;
}

你可能感兴趣的:(欧拉函数)