杜教筛提高

神犇和蒟蒻
根据 μ ( n ) \mu(n) μ(n) 的定义,当 n n n 为大于 1 1 1的完全平方数时 μ ( n ) = 0 \mu(n)=0 μ(n)=0,当 n = 1 n=1 n=1 时 μ ( n ) = 1 \mu(n)=1 μ(n)=1。因此 ∑ i = 1 n μ ( i 2 ) = 1 \sum_{i=1}^n \mu(i^2)=1 ∑i=1n​μ(i2)=1。
对于 φ ( n ) \varphi(n) φ(n),根据经验,转化为约数的 φ \varphi φ 之和。即:
n = ∑ i ∣ n φ ( i ) n=\sum_{i|n}\varphi(i) n=∑i∣n​φ(i)
因此有:
∑ i = 1 n ∑ j ∣ i φ ( j ) i = ∑ i = 1 n i 2 = 1 6 n ( n + 1 ) ( 2 n + 1 ) \sum_{i=1}^n \sum_{j|i}\varphi(j)i=\sum_{i=1}^n i^2=\frac{1}{6}n(n+1)(2n+1) ∑i=1n​∑j∣i​φ(j)i=∑i=1n​i2=61​n(n+1)(2n+1)
换一种表达方法,先枚举约数,再枚举倍数:
∑ i = 1 n ∑ i ∣ j φ ( i ) j = ∑ i = 1 n φ ( i ) i ∑ j = 1 [ n / i ] j = 1 6 n ( n + 1 ) ( 2 n + 1 ) \sum_{i=1}^n \sum_{i|j}\varphi(i)j=\sum_{i=1}^n \varphi(i)i \sum_{j=1}^{[n/i]}j=\frac{1}{6}n(n+1)(2n+1) ∑i=1n​∑i∣j​φ(i)j=∑i=1n​φ(i)i∑j=1[n/i]​j=61​n(n+1)(2n+1)
不要忘了求解的目标:
∑ i = 1 n φ ( i ) i \sum_{i=1}^n \varphi(i)i ∑i=1n​φ(i)i
将其从式子中提出来,移项:
∑ i = 1 n φ ( i ) i = 1 6 n ( n + 1 ) ( 2 n + 1 ) + ∑ i = 1 [ n / 2 ] φ ( i ) i ( 1 − ∑ j = 1 [ n / i ] j ) \sum_{i=1}^n \varphi(i)i=\frac{1}{6}n(n+1)(2n+1)+\sum_{i=1}^{[n/2]}\varphi(i)i(1-\sum_{j=1}^{[n/i]}j) ∑i=1n​φ(i)i=61​n(n+1)(2n+1)+∑i=1[n/2]​φ(i)i(1−∑j=1[n/i]​j)
因此最终的答案为:
1 6 n ( n + 1 ) ( 2 n + 1 ) + ∑ i = 1 [ n / 2 ] φ ( i ) i ( 1 − 1 2 [ n / i ] ( [ n / i ] + 1 ) \frac{1}{6}n(n+1)(2n+1)+\sum_{i=1}^{[n/2]}\varphi(i)i(1-\frac{1}{2}[n/i]([n/i]+1) 61​n(n+1)(2n+1)+∑i=1[n/2]​φ(i)i(1−21​[n/i]([n/i]+1)
根据式子跑杜教筛即可。
时空复杂度 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32​)

#include<iostream>
#include<map>
using namespace std;
#define R register int
#define L long long
#define N 10000001
#define P 1000000007
int prime[664579],pre[N];
map<int,int>Q;
inline int Solve(int n){
	if(n<N){
		return pre[n];
	}
	if(Q.count(n)!=0){
		return Q[n];
	}
	int res=(1ll+n)*n%P*(n<<1|1)%P*166666668%P,r,lt=0,cur;
	for(R i=1;i<=n>>1;i=r+1){
		int tem=n/i;
		r=n/tem;
		cur=Solve(r);
		res+=(1-((1ll+tem)*tem>>1)%P)*(cur-lt)%P;
		if(res<0){
			res+=P;
		}else if(res>=P){
			res-=P;
		}
		lt=cur;
	}
	Q[n]=res;
	return res;
}
int main(){
	pre[1]=1;
	int n,ct=0;
	for(R i=2;i!=N;i++){
		if(pre[i]==0){
			pre[i]=i-1;
			prime[ct]=i;
			ct++;
		}
		for(R j=0;j!=ct&&i*prime[j]<N;j++){
			if(i%prime[j]==0){
				pre[i*prime[j]]=pre[i]*prime[j];
				break;
			}
			pre[i*prime[j]]=pre[i]*(prime[j]-1);
		}
		pre[i]=((L)pre[i]*i+pre[i-1])%P;
	}
	cin>>n;
	cout<<1<<endl<<Solve(n);
	return 0;
}
上一篇:20180322 对DataTable里面的数据进行去重


下一篇:欧拉定理