题解:P10186 [YDOI R1] Lattice

分析

首先,我们设定在 k k k 意义下的 x x x y y y,枚举它们。发现每一个贡献都是 ⌊ n max ⁡ ( x , y ) ⌋ 2 \lfloor\frac{n}{\max(x,y)}\rfloor^2 max(x,y)n2。设只需要计算一边,我们需要求:
∑ x = 2 n ∑ y = 1 i − 1 ⌊ n max ⁡ ( x , y ) ⌋ 2 \sum_{x=2}^{n}\sum_{y=1}^{i-1}\lfloor\frac{n}{\max(x,y)}\rfloor^2 x=2ny=1i1max(x,y)n2
以上式子还算重了很多,考虑限制看到的第一个点计算贡献,即多加一个条件 [ gcd ⁡ ( x , y ) = 1 ] [\gcd(x,y)=1] [gcd(x,y)=1]
∑ x = 2 n ∑ y = 1 x − 1 [ gcd ⁡ ( x , y ) = 1 ] ⌊ n x ⌋ 2 \sum_{x=2}^{n}\sum_{y=1}^{x-1}[\gcd(x,y)=1]\lfloor\frac{n}{x}\rfloor^2 x=2ny=1x1[gcd(x,y)=1]xn2
把第二个 ∑ \sum 变成欧拉函数的形式,得:
∑ x = 2 n φ ( x ) ⌊ n x ⌋ 2 \sum_{x=2}^{n}\varphi(x)\lfloor\frac{n}{x}\rfloor^2 x=2nφ(x)xn2
最后的答案不是这一个。由于只计算了一边,所以要乘以 2 2 2。而且中间的对角线也需要算进去,贡献为 n × n n\times n n×n

由于 n n n 可以达到 2 31 − 1 2^{31}-1 2311,所以欧拉函数需要使用杜教筛优化,整个式子的计算需要使用数论分块。

代码

#include<bits/stdc++.h>
#define MAXN 1664511
#define MOD 1000000007
using namespace std;
typedef long long ll;
vector<int> prim;
bool flag[MAXN];
int phi[MAXN];
ll pre[MAXN];
map<int,ll> mp;
inline void prework(){
	phi[1]=1;
	for(int i=2;i<MAXN;++i){
		if(!flag[i]){
			prim.push_back(i);
			phi[i]=i-1;
		}
		for(int j=0;j<prim.size()&&i*prim[j]<MAXN;++j){
			flag[i*prim[j]]=true;
			if(i%prim[j]){
				phi[i*prim[j]]=phi[i]*(prim[j]-1);
			}else{
				phi[i*prim[j]]=phi[i]*prim[j];
				break;
			}
		}
	}
	for(int i=1;i<MAXN;++i){
		pre[i]=(pre[i-1]+phi[i])%MOD;
	}
}
ll varphi(int n){
	if(n<MAXN){
		return pre[n];
	}
	if(mp[n]){
		return mp[n];
	}
	ll res=1ll*n*(n+1ll)>>1ll;
	for(int l=2,r=0;l<=n;l=r+1){
		r=n/(n/l);
		(res-=varphi(n/l)*1ll*(r-l+1)%MOD)%=MOD;
	}
	return mp[n]=(res%MOD+MOD)%MOD;
}
int main(){
	prework();
	int n;
	scanf("%d",&n);
	ll res=0;
	for(int l=2,r=0;l<=n;l=r+1){
		r=n/(n/l);
		(res+=1ll*(n/l)*(n/l)%MOD*(varphi(r)-varphi(l-1)))%=MOD; 
	}
	printf("%lld\n",(2ll*res+1ll*n*n)%MOD);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值