BZOJ4916: 神犇和蒟蒻

杜教筛

题目传送门

我会第一问!

因为当 i i i中有平方因子时 μ ( i ) = 0 \mu(i)=0 μ(i)=0,所以第一问的答案就是 1 1 1

第二问有 φ ( i 2 ) = i ⋅ φ ( i ) \varphi(i^2)=i\cdot\varphi(i) φ(i2)=iφ(i)。因为 φ ( i ) = i ∏ ( 1 − 1 p i ) \varphi(i)=i\prod(1-\frac1{p_i}) φ(i)=i(1pi1),乘上 i i i后质因子并没有变,所以直接乘 i i i

那么就是求 ∑ i ⋅ φ ( i ) \sum i\cdot\varphi(i) iφ(i),而 φ ∗ 1 = I d \varphi*1=Id φ1=Id。所以我们设 g ( i ) = 1 g(i)=1 g(i)=1,由杜教筛的结论, S ( n ) = ∑ i 2 − ∑ i = 2 n S ( ⌊ n i ⌋ ) S(n)=\sum i^2-\sum_{i=2}^nS(\lfloor\frac ni\rfloor) S(n)=i2i=2nS(in)。除法分块递归做就好了。

然鹅 n ≤ 1 e 9 n\leq 1e9 n1e9,要用map记录答案。然鹅map太慢了,要预处理 n ≤ 1 e 9 2 / 3 = 1 e 6 n\leq 1e9^{2/3}=1e6 n1e92/3=1e6的答案。这样时间复杂度是 n 2 / 3 n^{2/3} n2/3的,我也不知道为什么。

代码:

#include<map>
#include<cstdio>
#include<algorithm>
#define N 100001
using namespace std;
typedef long long LL;
const LL iv6=166666668;
LL n,P=1e9+7,phi[N],p[N]; bool f[N]; map <LL,LL> s;
inline void Make(){
	phi[1]=1;
	for (LL i=2;i<N;i++){
		if (!f[i]) p[++p[0]]=i,phi[i]=i-1;
		for (int j=1,v;j<=p[0]&&i*p[j]<N;j++){
			f[v=i*p[j]]=true;
			if (i%p[j]==0){ phi[v]=phi[i]*p[j]; break; }
			phi[v]=phi[i]*phi[p[j]];
		}
	}
	for (LL i=2;i<N;i++) phi[i]=(phi[i]*i%P+phi[i-1])%P;
}
LL calc(LL n){
	if (n<N) return phi[n]; if (s.count(n)) return s[n];
	LL ans=n*(n+1)%P*(n*2+1)%P*iv6%P;
	for (LL l=2,r;l<=n;l=r+1)
		r=n/(n/l),(ans-=(l+r)*(r-l+1)/2%P*calc(n/l)%P+P)%=P;
	return s[n]=(ans+P)%P;
}
int main(){ return scanf("%lld",&n),puts("1"),Make(),printf("%lld\n",calc(n)),0; }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值