矩阵求和 题解(欧拉函数)
题目链接
题目描述
经过重重笔试面试的考验,小明成功进入 Macrohard 公司工作。
今天小明的任务是填满这么一张表:
表有 n 行 n 列,行和列的编号都从1算起。
其中第 i 行第 j 个元素的值是 gcd(i, j)的平方,
gcd 表示最大公约数,以下是这个表的前四行的前四列:
1 1 1 1
1 4 1 4
1 1 9 1
1 4 1 16
小明突然冒出一个奇怪的想法,他想知道这张表中所有元素的和。
由于表过于庞大,他希望借助计算机的力量。
「输入格式」
一行一个正整数 n 意义见题。
「输出格式」
一行一个数,表示所有元素的和。由于答案比较大,请输出模 (10^9 + 7)(即:十亿零七) 后的结果。
「样例输入」
4
「样例输出」
48
「数据范围」
n <= 10^7
题目思路
本质上就是找有多少个\((i,j)\)使得\(\gcd(i,j)=k\)
可以转化为\(n/k\)以内有几对\(gcd(i,j)=1\)
那就是\(phi[i]\)的前缀和,然后求总和
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=1e7+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int n,num;
int phi[maxn],prime[maxn];
ll pre[maxn];
bool flag[maxn];
void euler(int n){
phi[1]=1;//1要特判
pre[1]=1;
for (int i=2;i<=n;i++){
if (flag[i]==0){//这代表i是质数
prime[++num]=i;
phi[i]=i-1;
}
for (int j=1;j<=num&&prime[j]*i<=n;j++)//经典的欧拉筛写法
{
flag[i*prime[j]]=1;//先把这个合数标记掉
if (i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];//若prime[j]是i的质因子,则根据计算公式,i已经包括i*prime[j]的所有质因子
break;//经典欧拉筛的核心语句,这样能保证每个数只会被自己最小的因子筛掉一次
}else{
phi[i*prime[j]]=phi[i]*phi[prime[j]];//利用了欧拉函数是个积性函数的性质
}
}
pre[i]=pre[i-1]+2*phi[i];
}
}
signed main(){
scanf("%d",&n);
euler(n);
ll ans=0;
for(int i=1;i<=n;i++){
ans=(ans+pre[n/i]*i%mod*i)%mod;
}
printf("%lld\n",ans);
return 0;
}
不摆烂了,写题