LG模拟赛#1 T2 肯德基,powerful number,寻找构造函数的规律

正题

求 n n n 以内所有正整数的最大平方因子的和。答案对 2 64 2^{64} 264取模。

tips: x x x 是 y y y 的平方因子,当且仅当 x x x 是 y y y 的因子且 x \sqrt x x ​恰为整数。

显然设 F ( x ) F(x) F(x)为x的最大平方因子。
容易发现 F ( x ) F(x) F(x)是一个积性函数,且 F ( p k ) = p k − ( k m o d    2 ) F(p^k)=p^{k-(k\mod 2)} F(pk)=pk−(kmod2)
既然是求一个积性函数的前缀和,自然就想到了使用杜教筛或者 m i n _ 25 min\_{25} min_25筛来求解,很遗憾不能通过此题。
还有一种新方法是powerful number,它能在快速计算构造函数G的前缀和的情况下,用 O ( n ) O(\sqrt n) O(n ​)的时间算出前缀和。可以先参考我这一篇Blog
这题则可以构造 G ( x ) = 1 , H ∗ G = F G(x)=1,H*G=F G(x)=1,H∗G=F
则答案为 ∑ i = 1 n H ( i ) ( n / i ) \sum_{i=1}^n H(i)(n/i) ∑i=1n​H(i)(n/i)
如果我们暴力枚举出每一个powerful number并进行求解,那么时间复杂度是 O ( T n ) O(T\sqrt n) O(Tn ​)的,依然不能通过此题。
我们尝试找规律?
由于 H = F / G H=F/G H=F/G,且这个G是一个常值函数1,所以H是一个积性函数且在质数的指数幂上是F的差分
为什么这么说,举个例子 F ( p k ) = ∑ i = 0 k G ( p i ) H ( p k − i ) = ∑ i = 0 k H ( p i ) F(p^k)=\sum_{i=0}^k G(p^i)H(p^{k-i})=\sum_{i=0}^k H(p^i) F(pk)=∑i=0k​G(pi)H(pk−i)=∑i=0k​H(pi),所以 F F F在质数的指数幂上是 H H H的前缀和,而 H H H则是 F F F的差分。
所以可以轻松得到 H ( p 2 k ) = p 2 k − 2 ( p 2 − 1 ) , H ( p 2 k + 1 ) = 0 H(p^{2k})=p^{2k-2}(p^2-1),H(p^{2k+1})=0 H(p2k)=p2k−2(p2−1),H(p2k+1)=0
哦!
所以 H H H只有在完全平方数有值,那么式子就更简单了:
∑ i = 1 n H ( i 2 ) ⌊ n i 2 ⌋ \sum_{i=1}^{\sqrt n}H(i^2)\lfloor \frac{n}{i^2}\rfloor ∑i=1n ​​H(i2)⌊i2n​⌋
用平凡的整除分块写一写,发现时间复杂度好像不对,却发现过了?
原因就在于后面的这个分块对象,可以帮助我们将时间复杂度降到 O ( n 1 / 3 ) O(n^{1/3}) O(n1/3)。
分类讨论一下就可:
当 i 2 < = n 2 / 3 i^2<=n^{2/3} i2<=n2/3时, i < = n 1 / 3 i<=n^{1/3} i<=n1/3,这部分只需要 O ( n 1 / 3 ) O(n^{1/3}) O(n1/3)就可以完成。
当 i 2 > n 2 / 3 时 i^2>n^{2/3}时 i2>n2/3时, ⌊ n i 2 ⌋ < = n 1 / 3 \lfloor \frac n {i^2}\rfloor<=n^{1/3} ⌊i2n​⌋<=n1/3,这部分也只需要 O ( n 1 / 3 ) O(n^{1/3}) O(n1/3)就可以完成,另外,听说求sqrt时间复杂度为 O ( 1 ) O(1) O(1)

#include<bits/stdc++.h>
using namespace std;

#define ull unsigned long long
const int N=10000010;
int T,p[N];
long long n;
bool vis[N];
ull h[N];

int main(){
	scanf("%d",&T);
	n=10000000;h[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]) p[++p[0]]=i,h[i]=1ll*i*i-1;
		for(int j=1;j<=p[0] && i*p[j]<=n;j++){
			vis[i*p[j]]=true;
			if(i%p[j]==0) {h[i*p[j]]=h[i]*p[j]*p[j];break;}
			h[i*p[j]]=h[i]*h[p[j]];
		}
	}
	for(int i=2;i<=n;i++) h[i]+=h[i-1];
	while(T--){
		scanf("%lld",&n);
		int l=1,r=0;
		ull ans=0;
		while(1ll*l*l<=n){
			r=sqrtl(n/(n/l/l));
			ans+=(h[r]-h[l-1])*(n/l/l);
			l=r+1;
		}
		printf("%llu\n",ans);
	}
}
上一篇:PyQt5:PyQt初体验


下一篇:文件流FileStream