题解 P8670 [蓝桥杯 2018 国 B] 矩阵求和
题目描述
具体思路
solution 1
显然可以每次枚举
令
然后进行莫比乌斯反演。
交换求和顺序,由于先枚举
令:
有:
显然
时间复杂度
这个复杂度跑
注意
平方和公式:
由于要对
同时数论分块的时候,用平方和公式要记得乘
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e7;
const int mod=1e9+7;
int v[N+5],prime[N+5],pr;
int mu[N+5];LL sum[N+5];
LL qpow(LL a,LL b){
LL ans=1%mod;a%=mod;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;b>>=1;
}
return ans;
}
void init(int n){
memset(v,0,sizeof(v));pr=0;
mu[1]=1;
for(int i=2;i<=n;i++){
if(!v[i]){
prime[++pr]=i;
mu[i]=-1;
}
for(int j=1;j<=pr&&i*prime[j]<=n;j++){
v[i*prime[j]]=1;
if(i%prime[j]==0){
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=n;i++){
sum[i]=(sum[i-1]+mu[i])%mod;
}
}
LL block(LL n){
LL ans=0;
for(LL l=1,r=0;l<=n;l=r+1){
r=n/(n/l);
ans=(ans+(sum[r]-sum[l-1])%mod*(n/l)%mod*(n/l)%mod+mod)%mod;
}
return ans;
}
LL f(LL n){
return n*(n+1)%mod*(2*n+1)%mod*qpow(6,mod-2)%mod;
}
LL calc(LL n){
LL ans=0;
for(LL l=1,r=0;l<=n;l=r+1){
r=n/(n/l);
ans=(ans+(f(r)-f(l-1))%mod*block(n/l)%mod+mod)%mod;
}
return ans;
}
int main(){
LL n;scanf("%lld",&n);
init(n);
printf("%lld\n",calc(n));
return 0;
}
solution2
我们回到这个式子:
我们考虑:
我们运用数形结合的思想,把这个东西看作是平面上有
这个时候我们使用几何直观,沿着对角线把这些点分成两部分。
那么式子就变成了:
显然另一部分是对称的,同时要减去算了两遍的
根据欧拉函数的定义,有:
把这个式子带回去,有:
令:
有:
显然可以数论分块做。
时间复杂度
只用跑一次数论分块,时间复杂度为:
不过题解区又是让我很迷的做法,竟然不用数论分块而是用暴力
注意
平方和公式:
由于要对
同时数论分块的时候,用平方和公式要记得乘
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e7;
const int mod=1e9+7;
int v[N+5],prime[N+5],pr;
int phi[N+5];LL sum[N+5];
LL qpow(LL a,LL b){
LL ans=1%mod;a%=mod;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;b>>=1;
}
return ans;
}
void init(int n){
memset(v,0,sizeof(v));pr=0;
phi[1]=1;
for(int i=2;i<=n;i++){
if(!v[i]){
prime[++pr]=i;
phi[i]=i-1;
}
for(int j=1;j<=pr&&i*prime[j]<=n;j++){
v[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for(int i=1;i<=n;i++){
sum[i]=(sum[i-1]+phi[i])%mod;
}
for(int i=1;i<=n;i++){
sum[i]=sum[i]*2%mod;
}
}
LL f(LL n){
return n*(n+1)%mod*(2*n+1)%mod*qpow(6,mod-2)%mod;
}
LL block(LL n){
LL ans=0;
for(LL l=1,r=0;l<=n;l=r+1){
r=n/(n/l);
ans=(ans+(f(r)-f(l-1))%mod*(sum[n/l]-1)+mod)%mod;
}
return ans;
}
int main(){
LL n;scanf("%lld",&n);
init(n);
printf("%lld",block(n));
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】